Object函式的不常用的內建方法
一、Object.preventExtensions
1、定義:Object.preventExtensions()方法用於將一個物件設定為不可擴充套件,也就是不能再為其新增新的屬性。
2、語法
Object.preventExtensions(obj);
引數
obj:要配置為不可擴充套件的物件
返回值
被設定為不可配置的物件
物件預設是可擴充套件的,即可以新增新的屬性。如果一個物件被配置為不可擴充套件,則無法新增新的屬性,這是一個不可逆的操作。不可擴充套件的物件仍然可以刪除已有的屬性(取決於屬性的可配置性),但如果嘗試新增新的屬性到不可擴充套件物件,會引發TypeError異常(嚴格模式)或靜默失敗。
Object.preventExtensions()僅阻止新增自身的屬性。但屬性仍然可以新增到物件原型,而這個不可擴充套件的物件同樣會繼承這些後來新增的原型物件的屬性。
在ES5中,如果引數不是一個物件型別,將丟擲一個TypeError異常。
在ES6中,非物件引數將被視為一個不可擴充套件的普通物件,因此會被直接返回。
3、示例
示例1:配置物件為不可擴充套件
var obj = { a: 1 }; var obj2 = Object.preventExtensions(obj); obj2 === obj; // true 方法返回的物件仍是原物件 obj.b = 2; // 非嚴格模式下靜默失敗 obj.b; // undefined Object.defineProperty(obj, 'c', { value: 3, writable: true, enumerate: true, configuration: true }); obj.c; // undefined
示例2:傳入非物件型別的值
var str = 'abcd';
Object.preventExtensions(str); // "abcd" 直接返回
二、Object.isExtensible
1、定義:Object.isExtensible()方法用於判斷一個物件是否是可擴充套件的。
2、語法
Object.isExtensible(obj);
引數
要判斷可擴充套件性的物件
返回值
一個布林值,表明物件是否可擴充套件。
預設情況下,物件都是可以擴充套件的,即物件可以新增新的屬性和方法。使用Object.preventExtensions()、Object.seal()和Object.freeze()方法都可以標記物件為不可擴充套件。
在ES5中,如果引數是非物件型別,會丟擲TypeError異常。
在ES6中,如果引數是非物件型別,則會認為是一個不可擴充套件的普通物件,因此會返回false。
3、示例
示例:測試物件的可擴充套件性
var obj = {};
Object.isExtensible(obj); // true
Object.preventExtensions(obj);
Object.isExtensible(obj); // false
var obj2 = Object.create(obj);
Object.isExtensible(obj2); // true 原型物件不可擴充套件,不會影響繼承物件
var obj3 = Object.seal({});
Object.isExtensible(obj3); // false
var obj4 = Object.freeze({});
Object.isExtensible(obj4); // false
三、Object.seal
一、定義:Object.seal()方法用於密封一個物件,即將物件設定為不可擴充套件,同時將物件的所有自有屬性都設定為不可配置(包括Symbol值的屬性)。也就是說,不能給物件新增新的屬性和方法,也不能刪除現有的屬性和方法、不能修改現有屬性和方法的配置。但如果物件的屬性和方法是可寫的,那該屬性和方法仍然可以修改。
二、語法
Object.seal(obj);
引數
obj:要被密封的物件
返回值
被密封的物件
該操作不會影響從原型物件繼承來的屬性和方法,即隻影響自有的屬性和方法。一旦物件被密封,則不能修改其屬性和方法的配置,一個數據屬性不能被重新定義成訪問器屬性,也不能從訪問器屬性修改為資料屬性。
在ES5中,如果傳遞給方法的引數不是一個物件,會丟擲TypeError異常。
在ES6中,如果傳遞給方法的引數不是一個物件,則會被視為已被密封的普通物件,直接返回它。
3、示例
示例1:密封一個物件
var obj = {
a: 1,
b: function () { console.log(2); },
[Symbol('c')]: 3
};
Object.getOwnPropertyDescriptors(obj);
/*
{
a: {value: 1, writable: true, enumerable: true, configurable: true},
b: {value: ƒ, writable: true, enumerable: true, configurable: true},
Symbol(c): {value: 3, writable: true, enumerable: true, configurable: true}
}
*/
Object.seal(obj);
Object.getOwnPropertyDescriptors(obj);
/*
{
a: {value: 1, writable: true, enumerable: true, configurable: false},
b: {value: ƒ, writable: true, enumerable: true, configurable: false},
Symbol(c): {value: 3, writable: true, enumerable: true, configurable: false}
}
*/
示例2:嘗試修改一個密封物件
var obj = {
a: 1,
b: function () { console.log(2); },
[Symbol.for('c')]: 3
};
obj.a; // 1
obj.b(); // 2
obj[Symbol.for('c')]; // 3
Object.seal(obj);
// 嘗試刪除一個屬性
delete obj.a; // false, 靜默失敗,嚴格模式下TypeError
obj.a; // 1
// 嘗試修改一個屬性
obj.a = 10;
obj.a; // 10 修改成功,密封操作只修改屬性的可配置性,不影響可寫性
// 嘗試修改一個方法
obj.b = function () { return 20; }
obj.b(); // 20 修改成功,密封操作只修改方法的可配置性,不影響可寫性
// 嘗試修改資料屬性成訪問器屬性
Object.defineProperty(obj, 'a', {
get: function () { return 1; }
};
// TypeError: Cannot redefine property: a
四、Object.isSealed
1、定義:Object.isSealed()方法用於判斷一個物件是否是已密封的狀態。密封狀態是指一個物件是不可擴充套件的,且所有自有屬性和方法都是不可配置的。
2、語法
Object.isSealed(obj);
引數
obj:要檢查的物件。
返回值
返回一個布林值,表示這個物件是否是已密封的。
在ES5中,如果傳遞給方法的引數不是一個物件,會丟擲TypeError異常。
在ES6中,如果傳遞給方法的引數不是一個物件,會認為其是一個密封物件,直接返回true。
3、示例
示例1:檢測一個物件是否密封
var obj = { a: 1 };
Object.isSealed(obj); // false
Object.seal(obj);
Object.isSealed(obj); // true
var obj2 = { b: 2 };
Object.preventExtensions(obj2);
Object.isSealed(obj2); // false
示例2:建立一個原生密封的物件
var obj = Object.defineProperty({}, 'a', {
value: 1,
enumerable: true,
writable: true,
configurable: false
});
Object.preventExtensions(obj);
Object.isSealed(obj); // true 注意這裡沒有調研Object.seal()方法
根據定義,只要物件所有自有的屬性和方法是不可配置的,且物件本身是不可擴充套件的,即認為物件是密封的。因此,根據示例2我們可以知道,只要符合上述條件,不一定要呼叫Object.seal()方法也可以建立一個密封物件。
五、Object.freeze
1、定義:
Object.freeze()方法用於凍結一個物件。即將物件設定為不可擴充套件、將物件的所有自有的屬性和方法(包括Symbol值的屬性和方法)配置為不可配置、不可寫。
2、語法
Object.freeze(obj);
引數
obj:要凍結的物件
返回值
已凍結的物件
該操作不會影響從原型物件繼承來的屬性和方法,即隻影響自有的屬性和方法。一旦物件被凍結,其自身的所有屬性都不可能以任何方式被修改。任何修改嘗試都會失敗,無論是靜默地還是通過丟擲TypeError異常。
3、示例
示例1:凍結一個物件
var obj = {
a: 1,
b: function () { console.log(2); },
[Symbol('c')]: 3
};
Object.getOwnPropertyDescriptors(obj);
/*
{
a: {value: 1, writable: true, enumerable: true, configurable: true},
b: {value: ƒ, writable: true, enumerable: true, configurable: true},
Symbol(c): {value: 3, writable: true, enumerable: true, configurable: true}
}
*/
Object.freeze(obj);
Object.isExtensible(obj); // false
Object.getOwnPropertyDescriptors(obj);
/*
{
a: {value: 1, writable: false, enumerable: true, configurable: false},
b: {value: ƒ, writable: false, enumerable: true, configurable: false},
Symbol(c): {value: 3, writable: false, enumerable: true, configurable: false}
}
*/
示例2:嘗試通過setter修改凍結物件的屬性值
var obj = {
a: 1,
get next() { return this.a++; },
set next(value) {
if (value >= this.a) {
this.a = value;
}
}
};
Object.getOwnPropertyDescriptors(obj);
/*
{
a: {value: 1, writable: true, enumerable: true, configurable: true},
next: {get: ƒ, set: ƒ, enumerable: true, configurable: true}
}
*/
obj.next; // 1
obj.a; // 2
Object.freeze(obj);
Object.getOwnPropertyDescriptors(obj);
/*
{
a: {value: 2, writable: false, enumerable: true, configurable: false}
next: {get: ƒ, set: ƒ, enumerable: true, configurable: false}
}
*/
obj.next; // 2
obj.next; // 2
obj.next; // 2
obj.a; // 2
obj.next = 10; // 修改失敗
obj.next; // 2
obj.a; // 2
示例3:凍結陣列物件
var array = [1, 2, 3, 4, 5, 6];
Object.freeze(array);
// 嘗試插入一個元素
array.push(7); // Cannot add property 6, object is not extensible
// 嘗試刪除一個元素
array.pop(); // Cannot delete property '5' of [object Array]
// 嘗試縮小陣列長度
array.length = 2; // 靜默失敗
array.length; // 6
array; // [1, 2, 3, 4, 5, 6];
// 嘗試擴大陣列長度
array.length = 10; // 靜默失敗
array.length; // 6
array; // [1, 2, 3, 4, 5, 6];
// 嘗試修改陣列已有元素
array[1] = 10; // 靜默失敗
array[1]; // 2
六、Object.isFrozen
1、定義:Object.isFrozen()方法用於判斷一個物件是否已凍結。
2、語法
Object.isFrozen(obj);
引數
obj:要判斷是否凍結的物件。
返回值
返回一個布林值表明物件是否已凍結。
在ES5中,如果傳遞給方法的引數不是一個物件,會丟擲TypeError異常。
在ES6中,如果傳遞給方法的引數不是一個物件,會認為其是一個凍結物件,直接返回true。
3、示例
示例1:檢測一個物件是否已凍結
var obj = { a: 1 };
Object.isFrozen(obj); // false
Object.freeze(obj);
Object.isFrozen(obj); // true
var obj2 = { b: 2 };
Object.preventExtensions(obj2);
Object.isFrozen(obj2); // false
示例2:建立一個凍結物件
var obj = Object.defineProperty({}, 'a', {
value: 1,
enumerable: true,
writable: false,
configurable: false
});
Object.defineProperty(obj, 'next', {
get:function () { return this.a;},
set:function (v) { this.a = v;},
configuration: false
});
Object.preventExtensions(obj);
Object.isFrozen(obj); // true 注意這裡沒有調研Object.freeze()方法
根據定義,只要物件所有自有的屬性和方法是不可配置和不可寫的,且物件本身是不可擴充套件的,即認為物件是凍結的。因此,根據示例2我們可以知道,只要符合上述條件,不一定要呼叫Object.freeze()方法也可以建立一個凍結物件。