本身在使用vue的过程当中常常会用到听到数据双向绑定
这个词,并且咱们还能够直接经过调用this.msg
(this表示vue实例),来获取data上的数据,之前一直不太明白为何能够这样获取,直到有一天我在论坛里看到了寻找海蓝96
这位大佬写的文章,才明白其原理,因此在此记录一下。vue
数据属性主要是用于对数据的描述。数据属性主要有如下4个特性。
一、Configurable:(字面意思是可配置的,我理解为可操做(删除、修改))表示可否经过delete操做来删除属性,以及可否修改属性,或者可否将属性修改成访问器属性。直接定义在对象上的属性,该特性值默认为true。
二、Enumerable:字面意思是可枚举的,表示可否经过for-in循环来遍历属性。直接在对象上定义的属性,该特性值默认为true。
三、Writable:表示可否修改属性的值。直接定义在对象上的该特性值默认也为true。
四、Value:这个特性包含着属性的数据值。对对象属性的读写操做都是在这个特性上。该特性的默认值为undefined。函数
想要修改上面的4个特性就得调用Object.defineProperty(obj,key,descriptor)方法,descriptor表示的是一个对象,对象中的属性必须是这四个特性中的一项或多项。this
注意: 一、屡次调用Object.defineProperty()方法修改同一个属性,只要把configurable特性设置为false后,就不能再把它变成可配置的了(再次调用Object.defineProperty()将configurable特性设置为true会报错),即这个过程是不可逆的,不能再对对象属性进行delete操做,可是还能够对对象属性进行修改操做。spa
Object.defineProperty(obj,"name",{
configurable:false,
enumerable:true,
writable:true,
value:"james"
});
delete obj.name;
console.log(obj);//{name: "james"},可见不能对obj进行删除操做了。
obj.name="test";
console.log(obj.name);//test 仍是能够对属性进行修改
复制代码
二、调用Object.defineProperty()方法时,若是不指定Configurable、Enumerable和writable等特性的值,默认为false。双向绑定
访问器属性也有4个。可是不包含数据值
一、Configurable:(字面意思是可配置的,我理解为可操做(删除、修改))表示可否经过delete操做来删除属性,以及可否修改属性,或者可否将属性修改成访问器属性。直接定义在对象上的属性,该特性值默认为true。
二、Enumerable:字面意思是可枚举的,表示可否经过for-in循环来遍历属性。直接在对象上定义的属性,该特性值默认为true。
三、Get:在读取属性时调用的函数。 默认值为undefined。
四、Set:在写入属性时调用的函数。的默认值为undefined。code
注意:不能使用Object.defineProperty()方法同时修改默认数据属性和访问器属性。即set和get访问器属性不能与writable以及value特性共存。对象
Object.defineProperty(obj,"name",{
configurable:true,
enumerable:true,
writable:true,
value:"james",
get(){
return this.val;
},
set(newVal){
this.val=newval;
}
});
//Uncaught TypeError: Invalid property descriptor. Cannot both specify accessors and a value or writable attribute, #<Object>
复制代码
我的以为数据属性和访问器属性的Configurable和Enumerable没什么区别。访问器属性主要用的是Get和Set这两个。ip
能够经过Object.defineProperty()实现简单的数据双向绑定。实现代码以下:ci
<input id="test1"/>
<input id="test2"/>
<script>
let obj={};
Object.defineProperty(obj,"name",{
configurable:true,
enumerable:true,
writable:true,
// value:"",
set(newValue){
document.querySelector("#test1").value=newValue;
document.querySelector("#test2").value=newValue;
},
get(){
return obj["name"];
}
});
document.addEventListener("keyup",function(e){
obj.name=e.target.value;
})
</script>
//经过操做能够发现,在test1中输入会改变test2中的值,在test2中输入也能改变test1中的值。
复制代码
vue中为何能够直接经过this.msg获取到data中的msg,原理代码以下:get
class Vue{
constructor(options={}){
this.$options=options;
this._data=options.data;
let data=this._data;
Object.keys(data).forEach((key)=>{
this._proxy(key)
})
};
_proxy(key){
//以this作为obj,将data对象上的属性所有绑定到vue实例上来
Object.defineProperty(this,key,{
configurable:true,
enumerable:true,
get(){
return this._data[key];
},
set(newval){
this._data[key]=newval;
}
})
}
}
复制代码