es5 的Object.defineProperty() 用来给一个对象定义一个属性。vue的双向绑定原理就是基于defineProperty的访问器属性实现的。vue
Object.defineProperty(obj, key, descriptor)
须要定义传入三个参数,这样就能够给对象obj定义一个key。chrome
第三个参数是一个对象有六个键值。分别是: configurable(boolean, 默认true), enumerable(boolean, 默认true), writable(boolean, 默认true), value(any, 默认undefined), get(function, 默认undefined), set(function, 默认undefined) 。其中writable, value任意一个和get, set任一一个都不能够同时存在。为何呢? 关于红宝书上的介绍,一上来就是一段教科书的描述,比较晦涩。将defineProperty方法定义的属性分为两种类型:数据属性和访问器属性。 因此descriptor参数的不一样决定了相应的属性的类型。 故descriptor有两种方式函数
描述数据属性(平时用obj.name = '123', 其实就是默认用这种方式定义的):this
{ configurable: false, // 默认为true, 描述可否被改变,好比delete或者修改为访问器属性 enumerable: false, // 默认为true, 描述可否被 in 枚举,好比for-in writable: false, // 默认true, 描述是否能被更改 value: [1, 2, 3], // 默认undefined, 就是属性的值 }
描述访问器属性es5
{ configurable: false, // 默认为true, 描述可否被改变,好比delete或者修改为访问器属性 enumerable: false, // 默认为true, 描述可否被 in 枚举,好比for-in get: function() { return this.name }, // 默认undefined, getter函数 set: function(newVal) { this.name = newVal }, // 默认undefined, setter函数 }
直接在chrome下进行:3d
var obj = {}; Object.defineProperty(obj, 'name', { configurable: false, // 默认为true, 描述可否被改变,好比delete或者修改为访问器属性 enumerable: false, // 默认为true, 描述可否被for-in枚举 writable: false, // 默认true, 描述是否能被更改 value: 'wython' // 默认undefined, 就是属性的值 });
运行结果 能够看到是定义了一个属性name.这种方式和obj.name = 'wython'; 其实没啥区别。在这里面我把configrable, enumerable, writable改为false。 因此若是参数去改值,或者遍历, 都是不行的。双向绑定
for(const i in obj) { console.log(i) } // 结果: undefined delete obj.name; // 无效 obj.name = 'Another wython'; // 无效
Object.defineProperty(obj, '_name', { configurable: true, enumerable: true, get: function() { return this.name }, set: function(newVal) { // 咱们能够尝试更改name的值,由于是不可更改因此是无效的 this.name = newVal; } }) // 验证 obj._name = 1; // 无效,缘由是访问器属性监听的是不可更改的name属性
因此说访问器属性监听的是另外一个属性,若是监听的是自身,会报堆栈溢出的错误。code
好比:对象
Object.defineProperty(obj, '_self', { configurable: true, enumerable: true, get: function() { return this._self }, set: function(newVal) { // 咱们能够尝试更改name的值,由于是不可更改因此是无效的 this._self = newVal; } }) obj._self;
更多的实例,能够本身尝试。blog
说实话,defineProperty方法平时几乎不用。毕竟如今工做上不少东西已经实现好了。咱们能够用setter的这种方式触发notity。相似于观察者模式的方式监听属性,实现双向数据绑定的做用。小中见大,细节的东西也是很重要的。这个方法的兼容性是IE9. IE8下面有些问题。