关于Object.defineProperty

Object.defineProperty()是ES5的一个方法,vue.js的数据双向绑定便是通过这个方法实现的。所以defineProperty有必要了解一下。

参数

Object.defineProperty(obj, prop, descriptor)接受三个参数:

  • obj 是要定义属性的对象
  • prop 是要定义或修改的属性的名称
  • descriptor 是定义或修改属性的描述符

return value 返回值是绑定的对象

descriptor描述符

descriptor 里有许多选项:

1
var obj={};//先定义一个对象

value: 设置该属性值,默认为undefined。

1
2
3
4
Object.defineProperty(obj, 'key', {
value: 'stack'
});
console.log(obj.key);//'stack'

configurable: 为true时表示该属性可更改也可删除,默认为false

1
2
3
4
5
6
7
Object.defineProperty(obj'key', {
configurable:true,//可删除
value: 'stack'
});
delete obj[key];
console.log(obj.key);
//error:key is not defined

1
2
3
4
5
6
Object.defineProperty(obj'key', {
configurable:false,//不可删除
value: 'stack'
});
delete obj[key];
console.log(obj.key);//'stack'

enumerable: 为true时表示该属性在枚举时显示,默认为false。

1
2
3
4
5
6
7
Object.defineProperty(obj, 'key', {
enumerable:true,//可遍历
value: 'stack'
});
for(var i in obj){
console.log(obj[i]);//'stack'
}

1
2
3
4
5
6
7
Object.defineProperty(obj, 'key', {
enumerable:false,//不可遍历
value: 'stack'
});
for(var i in obj){
console.log(obj[i]);//不打印
}

writable: 为true时表示该属性的值可以使用赋值运算符进行更改,默认为false

1
2
3
4
5
6
Object.defineProperty(obj, 'key', {
writable:true,//可更改
value: 'stack'
});
obj.key+='123';
console.log(obj.key);//"stack123"

1
2
3
4
5
6
Object.defineProperty(obj, 'key', {
writable:false,//不可更改
value: 'stack'
});
obj.key+='123';
console.log(obj.key);//依然为"stack"

get:当你调取对象的这个属性时,会触发此函数。默认为undefined。

set:当你设置对象的这个属性时,会触发此函数。默认为undefined。

注意:在 descriptor 中不能 同时设置访问器 (get 和 set) 和 writable 或 value,否则会错,就是说想用(get 和 set),就不能用(wriable 或 value中的任何一个);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var keyValue=null;
Object.defineProperty(obj, 'key', {
get:function(){
console.log('你取到了值');
return keyValue;
},
set:function(value){
console.log('你设置了值'+value);
keyValue=value;
}
});
obj.key='stack';//打印 你设置了值stack
console.log(obj.key);//打印 你取到了值
//打印 stack

在上一篇水球动画插件里便用到了set和get,这也是一个简单的watcher实现。
我们实例化了一个水球后:

1
var a=new WaterPolo('canvas');

然后改变水球的水面高度,这时我们需要改变实例对象的options属性,改变对象指定属性,触发set函数:

1
2
3
4
var newOptions={
baseY:50//水面高度
};
a.options=newOptions;//改变options属性

1
2
3
4
5
6
7
8
Object.defineProperty(this, 'options', {
get: function() {
return options;
},
set: function(value) {
mergeOption(value,options);//调用扩展对象函数,当前值与存储在options中的对应值,如果发生变化,则将值更新
}
});

了解了Object.defineProperty()后,接下来就是解析Vue的observer和watcher了。