前言
vue.js中使用ES5的Object.defineProperty()實作資料的雙向綁定
Object.defineProperty()原理
Object.defineProperty()可以用來修改對象的屬性,也可以在對象上新建立一個屬性
文法
Object.defineProperty(obj, prop, descriptor)
參數: obj -> 被定義或修改屬性的對象
prop -> 要定義或修改的屬性名稱
descriptor -> 對屬性的描述
傳回值
函數将傳回傳遞給他的obj對象本身
描述符(descriptor)說明
該方法允許開發者精确的對對象屬性的定義和修改。通過正常指派進行屬性添加而建構的屬性會被枚舉器方法(如for..in循環或Object.keys方法)擷取,進而導緻屬性值被外部方法改變或删除。而Object.defineProperty()可以避免以上描述的情況,預設的,通過Object.defineProperty()添加的屬性是預設不可改變的。
屬性描述參數(descriptor)主要由兩部分構成:資料描述符(data descriptor)和通路器描述符(accessor descriptor)。資料描述符就是一個包含屬性的值,并說明這個值可讀或不可讀的對象;通路器描述符就是包含該屬性的一對getter-setter方法的對象。一個完整的屬性描述(descriptor)必須是這兩者之一,并且不可以兩者都有。
資料描述符
- value:屬性的值,預設為undefined
- writable:可重寫性,如果為false,屬性的值就不能被重寫, 隻能為隻讀了,預設為false
- configurable:可配置性,總開關,一旦為false,就不能再設定他的(value,writable,configurable),預設為false
- enumerable:可枚舉性,是否可枚舉(是否能在for...in循環中周遊出來或在Object.keys中列舉出來),預設為false
通路器描述符
- get:擷取資料時觸發
- set:設定資料時觸發
var person= {};
Object.defineProperty(person, "name", {
value: '張三'
})
console.log(person.name); // 張三
我們隻設定了 value,别的并沒有設定
但是第一次的時候 可以簡單的了解為(暫時這樣了解)它會預設幫我們把writable,configurable,enumerable都設上值,而且值還都是false。
也就是說,上面代碼和下面是等價的的(僅限于第一次設定的時候)。
var person = {};
Object.defineProperty(person ,"name",{
value: '張三',
writable :false,
enumerable: false,
configurable: false
});
console.log(person.name); // 張三
configurable
總開關,第一次設定 false 之後,第二次什麼設定也不行了,比如說
var person = {};
Object.defineProperty(person,"name",{
configurable: false
});
Object.defineProperty(person,"name",{
configurable: true
});
//error: Uncaught TypeError: Cannot redefine property: name
就會報錯了。。
注意上面講的預設值。。。如果第一次不設定它會怎樣。。會幫你設定為false。。是以。。第二次。再設定會報錯
writable
如果設定為fasle,就變成隻讀了,不能進行修改。。
var person = {};
Object.defineProperty(person, "name", {
value : '張三',
writable : false
}
);
console.log(person.name); // 列印 張三
person.name = '李四'; // 沒有錯誤抛出(在嚴格模式下會抛出,即使之前已經有相同的值)
console.log(person.name); // 列印 張三, 指派不起作用。
enumerable
屬性特性 enumerable 定義了對象的屬性是否可以在 for...in 循環和 Object.keys() 中被枚舉。
var person = {};
Object.defineProperty(person, "name", {
value : '張三',
enumerable: true
}
);
console.log(Object.keys(person)); // 列印 ["name"]
如果将enumerable改為false, for...in 類似
var person = {};
Object.defineProperty(person, "name", {
value : '張三',
enumerable: false
}
);
console.log(Object.keys(person)); // 列印 []
set 和 get
在 descriptor 中不能同時設定通路器(get 和 set)和 wriable 或 value,否則會錯,就是說想用 get 和 set,就不能用 writable 或 value 中的任何一個。
var person= {};
var temp = [];
Object.defineProperty(person, 'name', {
set: function(newVal) {
temp['name'] = newVal;
console.log('為person設定新的姓名:' + newVal);
},
get: function() {
var _name = temp['name'] || '預設姓名';
console.log('擷取person的姓名:' + _name);
return _name;
}
});
person.name = '張三'; // 列印 擷取person的姓名:張三
console.log(person.name) // 列印 擷取person的姓名:張三(如果不設定name,這裡會列印'預設姓名')
轉載于:https://www.cnblogs.com/kunmomo/p/9953215.html