JavaScript 提供了一個內(nèi)部數(shù)據(jù)結(jié)構(gòu),用來描述對象的屬性,控制它的行為,比如該屬性是否可寫、可遍歷等等。這個內(nèi)部數(shù)據(jù)結(jié)構(gòu)稱為“屬性描述對象”(attributes object)。每個屬性都有自己對應(yīng)的屬性描述對象,保存該屬性的一些元信息。
{
value: "zhang", //該屬性的屬性值,默認(rèn)為undefined。
writable: false, //表示屬性值(value)是否可改變(即是否可寫),默認(rèn)為true。
enumerable: true, // 表示該屬性是否可遍歷,默認(rèn)為true。如果設(shè)為false,會使得某些操作(比如for...in循環(huán)、Object.keys())跳過該屬性。
configurable: false, //表示可配置性,默認(rèn)為true。如果設(shè)為false,將阻止某些操作改寫該屬性,比如無法刪除該屬性,也不得改變該屬性的屬性描述對象(value屬性除外)。也就是說,configurable屬性控制了屬性描述對象的可寫性。
get: undefined, //表示該屬性的取值函數(shù)(getter),默認(rèn)為undefined。
set: undefined //表示該屬性的存值函數(shù)(setter),默認(rèn)為undefined。
}
對象上的方法
-
Object.getOwnPropertyDescriptor()
獲取屬性描述對象。它的第一個參數(shù)是一個對象,第二個參數(shù)是一個字符串,對應(yīng)該對象的某個屬性名。
let obj = { name: "zhang" }
Object.getOwnPropertyDescriptor(obj,"name")
{
value: "zhang",
writable: true,
enumerable: true,
configurable: true
}
//只能用于對象自身的屬性,不能用于繼承的屬性
-
Object.getOwnPropertyNames()
返回一個數(shù)組,成員是參數(shù)對象自身的全部屬性的屬性名,不管該屬性是否可遍歷。
let obj = { name: "zhang" }
Object.getOwnPropertyNames(obj) //["name"]
-
Object.defineProperty(),Object.defineProperties()
Object.defineProperty方法允許通過屬性描述對象,定義或修改一個屬性,然后返回修改后的對象,該方法接受三個參數(shù)(屬性所在的對象,屬性名(它應(yīng)該是一個字符串,屬性描述對象)
var obj = Object.defineProperty({}, 'p', {
value: 123,
writable: false,
enumerable: true,
configurable: false
});
obj.p // 123
如果一次性定義或修改多個屬性,可以使用Object.defineProperties方法。
var obj = Object.defineProperties({}, {
p1: { value: 123, enumerable: true },
p2: { value: 'abc', enumerable: true },
p3: { get: function () { return this.p1 + this.p2 },
enumerable:true,
configurable:true
}
});
obj.p1 // 123
obj.p2 // "abc"
obj.p3 // "123abc"
//定義了get或set,不能將writable屬性設(shè)為true,或者定義value屬性,
-
Object.prototype.propertyIsEnumerable()
判斷某個屬性是否可遍歷,返回一個布爾值。
let obj = { name: "zhang" }
obj.propertyIsEnumerable('name') // true
obj.propertyIsEnumerable('toString') // false
//繼承原型對象的屬性不可遍歷
元屬性
屬性描述對象的各個屬性稱為“元屬性”,因?yàn)樗鼈兛梢钥醋魇强刂茖傩缘膶傩浴ue 雙向數(shù)據(jù)綁定基于該操作。
- value
let obj = { name: "zhang" }
Object.getOwnPropertyDescriptor(obj, 'name').value
Object.defineProperty(obj, 'name', { value: "li" })
obj.name // li
- writable //決定了目標(biāo)屬性的值(value)是否可以被改變。
var obj = {};
Object.defineProperty(obj, 'name', {
value: "zhang",
writable: false
});
obj.name // zhang
obj.name = "li"
obj.name // zhang
- enumerable // 表示目標(biāo)屬性是否可遍歷。
var obj = {};
Object.defineProperty(obj, 'name', {
value: "zhang",
enumerable: false
});
obj.name // "zhang"
for (var key in obj) {
console.log(key);
}
// undefined
Object.keys(obj) // []
JSON.stringify(obj) // "{}"
- configurable // 是否可以修改屬性描述對象,configurable為false時,value、writable、enumerable和configurable都不能被修改。
var obj = Object.defineProperty({}, 'name', {
value: "zhang",
writable: false,
enumerable: false,
configurable: false
});
Object.defineProperty(obj, 'name', {value: "T"})
/// TypeError: Cannot redefine property: name
set && get
屬性還可以用存取器(accessor)定義。其中,存值函數(shù)稱為setter,使用屬性描述對象的set屬性;取值函數(shù)稱為getter,使用屬性描述對象的get屬性。
let obj = Object.defineProperty({}, 'name', {
get: function () {
return 'jack';
},
set: function (value) {
console.log('item: ' + value);
}
});
obj.name // "jacky"
obj.name = 123 // "item: 123"
.......................................................................
控制對象狀態(tài)
有時需要凍結(jié)對象的讀寫狀態(tài),防止對象被改變。JavaScript 提供了三種凍結(jié)方法,最弱的一種是Object.preventExtensions,其次是Object.seal,最強(qiáng)的是Object.freeze。
- Object.preventExtensions()
Object.preventExtensions方法可以使得一個對象無法再添加新的屬性
var obj = new Object();
Object.preventExtensions(obj);
Object.defineProperty(obj, 'name', {
value: 'zhang'
});
// TypeError: Cannot define property:name, object is not extensible.
obj.name = 1;
obj.name // undefined
- Object.isExtensible()
用于檢查一個對象是否使用了Object.preventExtensions方法。也就是說,檢查是否可以為一個對象添加屬性。
var obj = new Object();
Object.isExtensible(obj) // true
Object.preventExtensions(obj);
Object.isExtensible(obj) // false
- Object.seal()
使得一個對象既無法添加新屬性,也無法刪除舊屬性。
var obj = { name: 'zhang' };
Object.seal(obj);
delete obj.name;
obj.name // "zhang"
obj.text = 'world';
obj.text // undefined
//Object.seal實(shí)質(zhì)是把屬性描述對象的configurable屬性設(shè)為false
- Object.isSealed()
檢查一個對象是否使用了Object.seal方法
var obj = { name: 'AndyZhang' };
Object.seal(obj);
Object.isSealed(obj) // true
- Object.freeze()
使得一個對象無法添加新屬性、無法刪除舊屬性、也無法改變屬性的值,使得這個對象實(shí)際上變成了常量。
var obj = { name: 'AndyZhang' };
Object.freeze(obj);
obj.name = 'li';
obj.name // "zhang"
obj.text = 'hello';
obj.text // undefined
//obj對象進(jìn)行Object.freeze()以后,修改屬性、新增屬性、刪除屬性都無效了。
- Object.isFrozen()
檢查一個對象是否使用了Object.freeze方法
var obj = { name: 'AndyZhang' };
Object.freeze(obj);
Object.isFrozen(obj) // true