本身在使用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;
}
})
}
}
複製代碼