ES6(二)

ES5 - Object.defineProperty

简介: 

  ES5规范开始后续版本迭代,也在致力于做一件事,就是把js底层已有的功能,提供给开发者使用。Object.defineProperty 就是其中一个,此方法会可直接在一个对象上定义一个新的具有详细描述的属性,或者修改一个对象现有的属性,并返回这个对象

使用:

  object.defineProperty(对象,属性,描述符):

  描述符对,对象的属性进行详细描述:

    数据描述符:

      value: 'xxx' 属性值。默认''

      writable: true 是否可写。默认false

      configurable:true 是否可配置。默认false (可以通过delete 进行删除)

      enumerable:true 是否可枚举。默认false ( 可以for in 循环 )

    存取描述符:

      set: function(){} 属性访问器 进行写操作时调用该方法

      get:function(){} 属性访问器 进行读操作时调用该方法

var obj = {、
  name: ‘ccc’

}

// value ccc
// writable
obj.name = 'wew'

// configurable
delete obj.name
console.log( delete obj.name ) // true

// enumerable
for ( var prop in obj ) {
  console.log(prop)  
}

// 不可写  writable false

Function.prototype = {

  name: 'ccc'

}

// 不可配置的 通过var 定义的全局变量不能够删的

var a = 10

console.log( window.a )

// Object.prototype 的属性是不可被枚举的

var obj = {

  name: 'ccc',

  age: 12,

  __proto__: {

    sex: 'male'

  }

}

for ( var prop in Object.prototype ) {

  

}

// 天生就有属性了,就可读可写 可配置 可枚举
var obj = {

}

var tempValuie = ''
Object.dfineProperty( obj, 'name', {
    // value: 'ccc',     ( value、writable 不能和get set 同时使用 )
    // writable: false, (其他不写默认都是 false) 
    configurable: true,
    enumerable: true,

    get: function () {
      //return 'ddd'
        return tempValue
    }
    
    set: function ( newValue ) {
       template = newValue

  }
} )

console.log( obj.name ) // ddd ''
obj.name = 10
console.log( obj.name ) // 10

var obj = {

  // 其余默认, 比defineProperty 写起来方便

  tempValue = '2323',

  get name () {

    return this.tempValue

  },

  set name (newValue) {

    this.tempValue = newValue

  } 

}

注意:

  如果描述符中同时出现, value、writable,和 set、get两组的话,会出现异常。切记不要同时使用

作用:

  双向数据绑定的核心方法,主要做数据劫持操作(监控属性变化),同时是后期ES6中很多语法糖底层实现的核心方法

 

ES5 - 数据劫持

  VUE 双向数据绑定核心功能由 Observer、Compile、Watcher 三部分实现其中 Observer 部分功能实现有 Object.definePropertry实现

    Observer: 监测数据变化进行相应回调(数据劫持):

    实现一个简单的数据劫持,作为Object.defineProperty 的练习。从而引出Proxy & Reflect

 

<input type="text" id="demo" />
<div id="show"></div>
var oDiv = document.getElementById('show')
var oInput = document.getElementById('demo')

var oData = {
  valueobj: {
    value: 'duyi',
    name: 'hha'
  },
  value: 'ddd' ,
  name: 'hah'
}

oInput.oninput = function () {
    oDate.value = this.value
}

function upDate () {
  oDiv.innerText = oData.value  

}

upDate()

// 监控对象的某个属性是否发生改变
functrion Observer (data) {

    if (!data || typeof data != 'object') {
      retrun data
    }

    //for ( var prop in data ) {}
    //object.keys( data ) // 返回的是 将对象中的属性放在数组中[ 'value' , 'name']
    Object.keys(data).forEach( function (key) {
       definedReactive( data, key, data[key] )
    } )
}

function definedReactive ( data, key, val ) {
    Observer(val) // 属性值是对象的时候需要递归
    Object.definedProperty( data, key, {
        get () {
            return val
        },
        set ( newValue ) {
            if ( newValue == value ) return
            val = newValue
            unDate()
        }
    } )
}

Observer(oData)
        

// vue 处理数组
 
var arr = []
let { push } = Array.prototype
function upData () {
    console.log('更新')
} 

//
[
    'push',
    'pop'
]
// arr push pop unshift slice...
Object.defineProperty( Array.prototype, 'push', {
    value: (function () {
        return (...arg) => {
            push.apply( arr, arg )
            upData()
       }
    })()
} )

arr.push(1,2)
有缺点: 不能直接搞定数据
oData.aa = 10 新加的属性在Observe 后面不会更新,需要在新加属性后面 Observe

// Proxy Reflect 兼容性不好 vue 3。0

ES6变化 - Proxy & Reflect

let oData = {
  
  value: 'sss',
  _val: 'aaa'

}

let oProxyData = new Proxy( oData, {

  set ( target, key, value, receiver ) {
    Reflect.set( target, key, value )
    upDate()
  },

  get ( target, key, receiver ) {
    return Reflect.get( target, key )
  },

  has ( target, key ) {
    return key.indexOf( '_' ) != -1 false : key in target
  },

  deleteProperty () {

  }
} )

ES6 - Proxy & Reflect

  简介:

    植入代理模式的思想,以简洁易懂的方式控制对外部对象的访问

  总结:

    利用内置的 set、get 方法控制属性的读写功能用处较大

    其余 has deleteProperty... 等方法不太在工作开发中使用

    有兴趣可以去了解一下

    兼容不好

let oData = {
  val: ‘saas’  
}

let oProxyData = new Proxy(oData, {
  set (target, key, value, receiver) {
    Reflect.set( target, key, value )
    upDate()
  },
  get ( target, key, receiver ) {
    // target {val:‘saas’} 返回对象 oData
    // key “val” 返回属性
    // receiver Proxy {val: "saas"} 返回代理对象 new Proxy(...)
    
   //  return target[key]

    return Reflect.get(target, key)
  },
 has (targt, key) {
  return key.indexOf('_') != -1 ? false : key in target
},
deleteProperty () {

}
})
// 读写 控制 console.log( oProxyData.val ) function upDate () { console.log(' 更新了 ') }

 

ES5 - Class (构造函数)回顾

面向对象思想简介:

  面向过程目的在于把功能拆分成步骤,一环扣一环的完成,但是需求复杂到一定程度后,对开发者能力的挑战也是越来越强

  面向对象目的在于前期把功能拆分并抽象成不同的对象,聚焦于每个对象的能力和他们之间的配合,项目复杂后相对于面向过程来讲较为轻松一些

  举个例子:大象装冰箱

  面向对象的编程语言需要具备 封装 继承 多态,js不是面向对象的语言而是基于对象的语言,js中基本上一切皆是对象

ES5 - Class 回顾

回顾ES5;

  构造对象,私有属性、公有属性,私有属性继承,公有属性继承

// ES5 => ES6
// 公有属性(原型上)
Plane.prototype.fly = function () {
  console.log( 'fly' )
}
function Plane (name) {
  // 私有属性
  this.name = "普通飞机";
  this.blood = 100;
  this.fly = function () {
    console.log('fly')
  }
}

var oPlane = new Plane()

// 继承 扩展功能 (装饰者模式)
// 继承 继承原型 私有属性
//AttackPlane.prototype.__proto__ = Plane.prototype
Object.setPrototypeOf(AttackPlane.prototype, Plane.prototype)

AttackPlane.prototype.dan = function () {
  console.log('biubiu~')
}
function AttackPlane (name) {
  //this.name = '攻击机'
  //this.blood = 100
  // 借用构造函数的方式
  Plane.call( this, name )
}

 

ES6变化 - Class

核心变化

  class、constructor、static、extends、super

// 私有属性 公有属性(原型属性) 静态属性(函数属性)
class Plane {
  // ES7  静态属性 写法
  // static alive = 10
  static alive () {
    return true
  }

  // 私有属性
  constructor (name) {
    this.name = name || '普通飞机'
    this.blood = 100
  } 

  // 原型方法  
  fly () {
    console.log( ‘fly’ )
  }
  
  // ES7 私有属性 写法
  // name = 10
}

var oP= new Plane()
Plane.alive() // true

// ES6 继承方式 extends + super
class AttackPlane extends Plane{
  constructor (name) {
    super(name) // 相当于 Plane.call(this, name)
    this.logo = 'cc'
  }
  dan () {
    console.log('biubiu')
  }

}

ES6 Class

1. 必须要new

2. 通过class 定义的类  Plane.prototype 和 static 不能枚举

3. 静态属性要放到 Plane 非原型

 

ES6 - 模拟实现Class

  

functuion _classCallCheck ( _this, _constructor ) {
  if ( !(_this instanceof _constructor) ) {
    throw "TypeError: Class constructor Plane cannot be invoked without 'new'" 

}
// 暴露在全局下不太好
//function Plane () {

  //_classCallCheck( this, Plane )

  // 把私有属性 公有属性 静态属性
  
//}

// 处理公有属性和静态属性
// 
function _defineProperties ( target, prop ) {
  // Object.defineProperty
  props.forEach(function (ele) {
    // ele.key ele.value
    Object.defineProperty( target, ele.key, {
       value: ele.value,
       writable: true,
       configurable: true
    } )
  })
}

function _createClass ( _constructor, _prototypeProperties, _staticProperties ) {
  // 给原型上赋值
  if (_prototypeProperties) {
    _defineProperties( _constructor.prototype,  _prototypeProperties )
  }
  if (_staticProperties) {
    _defineProperties( _constructor, _staticProperties )
  }
}

var Plane = (function () {
  function Plane (name) {
    // 判断是否以new 的方式来执行
    _classCallCheck( this, Plane )
    this.name = name || '普通飞机'
    this.blood = 100
    
  }

  _createClass( Plane, [
    {
       key: 'fly',
       value: function () {
          console.log('fly')
       }
    }  
  ], [
     {
        key: 'alive',
        value: function () {
           return true
        }
      }
  ] )
  return Plane
})()

// 实现继承
function _inherit ( sub, sup ) {
  Object.setPrototypeOf( sub.prototype, sup.prototype )
}

var AttackPlane = ( function ( Plane ) {
  _inherit( AttackPlane, Plane )
  function AttackPlane ( name ) {
    _classCallCheck( this, Plane )
    var _this = this
    var that = Plane.call( _this, name )
    if ( typeof that == 'object' ) {
      _this = that
    }
    _this.logo = 'ds'
   return _this
  }

   _createClass( AttackPlane, [
    {
       key: 'dan',
       value: function () {
          console.log('biubiu')
       }
    }  
  ], [
     {
        key: 'alive',
        value: function () {
           return true
        }
      }
  ] )
  return AttackPlane
} )(Plane)

new Plane()

 ES7变化 - Class 提案属性

新特性:

   static property = xxx  静态属性

   property = xxx  私有属性

   @decorator 装饰器

提案特性需要下载:

  npm install @babel/plugin-proposal-decorators

需要配置:

  {

    "plugins": [

      ["@babel/plugin-proposal-decorators", { "legacy": true }],

      ["@babel/plugin-proposal-class-properties", { "loose": true }]

    ]

  }

calss Search {
  // ES7
  static num =  10
  // ES6
  static num () {
   return 6
  }
 
  constructor () {
    this.keyValue = ' '
  }
 //ES7  私有属性
  url = ‘urlA-’
  @readOnly
  getCount () {
    console.log('发送请求')
  }
}

 

ES7 - Decorator

// 张三

var oInput = document.getElementById('inp')
var oBtn = document.getElementById('btn')
var keyValue = ''
oInput.oninput = function () {
  keyValue = this.value
}

oBtn.onclick = function () {
 newGetContent( keyValue )
}

function getContent ( data ) {
  var url = 'url-A'
  console.log(url +  ‘发送网络请求,数据:‘ + data)
}

var newGetContent = dealFunc( getCountent )

// 李四
function dealFunc ( func ) {
  retrun functuion (data) {
    // 
    var urlB = 'urlB'
    consoloe.log(urlB +  ‘发送网络请求,数据:‘+ data )
    return func.apply( this, arguments )
    
  }

}

 

@Skin
class Search { constructor () {
this.keyValue = '' } @myReadOnly url = 'urlA-' //@dealData @dealData('张三')
getContent () { console.log(
this.url +'发送网络请求,数据:'+ this.keyValue ) } }

Decorators.js
// 装饰类
function Skin (target) {
target.aaa = 30 // Search.aaa 30
}

//
装饰私有属性 descript 没有value 只有 initializer, 原型的时候有 value 没initializer function myReadOnly ( proto, key, descriptor ) { console.log( proto, key, descriptor ) descriptor.writable = false console.log( descriptor.initializer() ) // urlA- descriptor.initializer = function () {   return 6                  // 6 改变了值               } } // 装饰原型上的属性 (箭头函数的时候是私有属性) function dealData ( proto, key, descriptor ) { console.log( proto, key, descriptor ) let oldValue = deescriptor.value // getContent() descriptor.value = function () { var urlB = 'urlB-' console.log(urlB + '发送网络请求,数据' + this.keyVal)   console.log(0) oldValue.apply( this, arguments ) } }
function dealData (ms ) {
  return function( proto, key, descriptor ) {
    console.log( proto, key, descriptor )
    let oldValue = deescriptor.value // getContent()
    descriptor.value = function () {
     var urlB = 'urlB-'
     console.log(urlB + '发送网络请求,数据' + this.keyVal + ms)
    console.log(0)
     oldValue.apply( this, arguments )
    }
  }
}

let oS
= new Search() oInput.oninput = function () { oS.keyValue = this.value } oBtn.onclick = function () { oS.getContent() }

 

posted @ 2020-03-05 18:52  izyk  阅读(187)  评论(0编辑  收藏  举报