一、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()方法也可以创建一个冻结对象。