通過Object.defineProperty()我們可以給Object對象定義屬性,同時還能更細粒度的控制該屬性。
基本語法:
Object.defineProperty(obj, prop, descriptor)
參數(shù):
- obj是要定義屬性的對象
- prop是要定義的屬性的名稱或Symbol
- descriptor是定義屬性的描述符,描述符有兩種形式,數(shù)據(jù)描述符和存取描述符
返回值:返回第一個參數(shù)obj
數(shù)據(jù)描述符是一個具有值的屬性,該值可以是可寫的,也可以是不可寫的。存取描述符是由 getter 函數(shù)和 setter 函數(shù)所描述的屬性。一個描述符只能是這兩者其中之一,但兩個不能同時使用。
上手
var obj = {};
Object.defineProperty(obj, 'foo', {
value: 'hello',
writable: true
});
console.log(obj); // {foo: "hello"}
Object.defineProperty(obj, 'bar', {
get: function() {
return 'world';
}
})
console.log(obj.bar); // world
上面代碼我們分別使用了不同的描述符定義屬性,用起來就是這么簡單,描述符中我們還能配置屬性的其他選項,其中兩個描述符共享configurable和enumerable選項:
- configurable:當為true時,屬性的描述符才能夠被更改,同時該屬性也能被刪除,默認false
- enumerable:當為true時,屬性才能被枚舉到,默認false
數(shù)據(jù)描述符有value和writable選項:
- value:該屬性對應的值,可以是數(shù)值,對象,函數(shù)等,默認
undefined,只能用于數(shù)據(jù)描述符 - writable:當為true時,才能使用賦值操作改變上面value的值,默認false
存取描述符有get和set選項:
- get:是一個無參的
getter函數(shù),訪問該屬性時會調(diào)用這個函數(shù),并且會傳入this對象,函數(shù)的返回值作為屬性值,如果沒有get,就會返回undefined - set:當修改屬性值時,這個函數(shù)會被調(diào)用,并且新的值會被作為參數(shù)傳進來,同時this對象指向被賦值的對象
匯總?cè)缦拢?/p>

描述符不能混用,即一個描述符同時擁有value或writable 和get 或 set 選項,否則會產(chǎn)生一個異常:
var obj = {};
Object.defineProperty(obj, 'bar', {
value: 'hello',
get: function() {
return 'world';
}
});
Uncaught TypeError: Invalid property descriptor.
Cannot both specify accessors and a value or writable attribute
我們通過幾個例子看看enumerable在不同枚舉方法中的表現(xiàn):
var obj = {}
Object.defineProperty(obj, 'a', {
value: 1,
enumerable: true
});
Object.defineProperty(obj, 'b', {
value: 2,
enumerable: false
});
Object.defineProperty(obj, 'c', {
value: 3, // enumerable默認為false
});
obj.d = 4 // enumerable默認為true
Object.defineProperty(obj, Symbol.for('e'), {
value: 5,
enumerable: true
});
Object.defineProperty(obj, Symbol.for('f'), {
value: 6,
enumerable: false
});
在for…in中:
for (var i in obj) {
console.log(i); // a, d
}
屬性名是symbol的不能被打印出來,enumerable是false也無法打印
在Object.keys()中:
Object.keys(obj); // ["a", "d"]
和上面一樣
在展開操作符…中:
var foo = {...obj}
console.log(foo); // {a: 1, d: 4, Symbol(e): 5}
enumerable為true的都能被解構出來,symbol也可以
通過點操作符和Object.defineProperty()添加屬性有什么區(qū)別:
var obj = {}
obj.foo = 2
// 等價于
Object.defineProperty(obj, 'foo', {
value: 1,
writable: true,
configurable: true,
enumerable: true
});