咳咳,各位同学,咱们今天来聊聊JavaScript对象控制欲的问题,啊不,是可扩展性的问题。具体来说,我们要深入了解一下 Object.seal()
和 Object.preventExtensions()
这两位“对象界包青天”,看看它们如何为对象伸张正义,维护对象秩序,防止对象被随意“改造”。
首先,咱们得明确一个概念:什么是对象的可扩展性?
在JavaScript里,对象就像一块橡皮泥,默认情况下,你可以随意捏它,加属性、删属性、改属性,随心所欲。这种“捏橡皮泥”的行为,就叫做对象的可扩展性。但是,有时候我们希望对象能保持“原汁原味”,不希望别人乱动它,这时候就需要用到 Object.seal()
和 Object.preventExtensions()
了。
一、 Object.preventExtensions()
:只许进,不许出!
Object.preventExtensions()
的作用非常简单粗暴:禁止给对象添加新的属性。就像在对象门口立了个牌子,上面写着“此路不通,禁止添加新属性!”。
咱们来看个例子:
let obj = {
name: '张三',
age: 30
};
Object.preventExtensions(obj);
obj.address = '北京'; // 试图添加新属性
console.log(obj.address); // 输出 undefined
delete obj.name; // 可以删除现有属性
console.log(obj.name); // 输出 undefined
obj.age = 31; // 可以修改现有属性
console.log(obj.age); // 输出 31
从上面的例子可以看出,使用 Object.preventExtensions()
之后:
- 不能添加新属性:试图添加
address
属性失败,因为obj.address
的值为undefined
。 - 可以删除现有属性:
name
属性可以成功删除。 - 可以修改现有属性:
age
属性可以成功修改。
所以,Object.preventExtensions()
就像一个门卫,只管阻止新属性的进入,对现有属性的修改和删除则睁一只眼闭一只眼。
注意事项:
Object.preventExtensions()
只能阻止对象本身添加新属性,不能阻止对象原型链上的属性添加。- 在严格模式下,试图给不可扩展的对象添加新属性会抛出
TypeError
错误。
二、 Object.seal()
:内外兼修,固若金汤!
Object.seal()
比 Object.preventExtensions()
更加严格,它不仅禁止添加新属性,还禁止删除现有属性,并将所有现有属性的 configurable
特性设置为 false
。这意味着,你不仅不能添加新属性,也不能删除现有属性,甚至连现有属性的 configurable
特性都不能修改了。
configurable
特性是干嘛的?简单来说,它决定了属性是否可以被删除,以及属性的特性是否可以被修改。如果 configurable
为 false
,则该属性无法被删除,也无法被重新配置(比如改变它的 writable
、enumerable
等特性)。
咱们再来看个例子:
let obj = {
name: '李四',
age: 25
};
Object.seal(obj);
obj.address = '上海'; // 试图添加新属性
console.log(obj.address); // 输出 undefined
delete obj.name; // 试图删除现有属性
console.log(obj.name); // 输出 '李四'
obj.age = 26; // 可以修改现有属性
console.log(obj.age); // 输出 26
Object.defineProperty(obj, 'name', {
configurable: true // 试图修改 configurable 特性
}); // 在严格模式下会抛出 TypeError,非严格模式下静默失败
console.log(Object.getOwnPropertyDescriptor(obj, 'name').configurable); // 输出 false
从上面的例子可以看出,使用 Object.seal()
之后:
- 不能添加新属性:试图添加
address
属性失败。 - 不能删除现有属性:试图删除
name
属性失败。 - 可以修改现有属性的值:
age
属性可以成功修改。 - 不能修改现有属性的
configurable
特性:试图修改name
属性的configurable
特性失败。
所以,Object.seal()
就像给对象穿上了一层盔甲,让它刀枪不入,固若金汤。
注意事项:
Object.seal()
只能作用于对象本身,不能阻止对象原型链上的属性被修改或删除。- 在严格模式下,试图删除或重新配置一个
configurable
为false
的属性会抛出TypeError
错误。
三、 Object.isExtensible()
和 Object.isSealed()
:探查虚实,明察秋毫!
既然我们有 Object.preventExtensions()
和 Object.seal()
这两把利剑来保护对象,那么如何判断一个对象是否已经被保护起来了呢? 这时候就需要用到 Object.isExtensible()
和 Object.isSealed()
这两个侦察兵了。
Object.isExtensible(obj)
:判断对象obj
是否可扩展,如果可以添加新属性,则返回true
,否则返回false
。Object.isSealed(obj)
:判断对象obj
是否已经密封,如果已经密封,则返回true
,否则返回false
。
咱们来看个例子:
let obj1 = { name: '王五' };
let obj2 = { name: '赵六' };
Object.preventExtensions(obj1);
Object.seal(obj2);
console.log(Object.isExtensible(obj1)); // 输出 false
console.log(Object.isExtensible(obj2)); // 输出 false
console.log(Object.isSealed(obj1)); // 输出 false
console.log(Object.isSealed(obj2)); // 输出 true
从上面的例子可以看出:
obj1
被Object.preventExtensions()
处理后,Object.isExtensible(obj1)
返回false
,表示obj1
不可扩展。obj2
被Object.seal()
处理后,Object.isSealed(obj2)
返回true
,表示obj2
已经密封。
四、 总结:选择合适的“保护策略”
Object.preventExtensions()
和 Object.seal()
都是用来保护对象的,但它们保护的程度不同。选择哪一个,取决于你的具体需求。
咱们用一个表格来总结一下它们的区别:
特性 | Object.preventExtensions() |
Object.seal() |
---|---|---|
禁止添加新属性 | 是 | 是 |
禁止删除现有属性 | 否 | 是 |
修改现有属性值 | 是 | 是 |
修改属性的 configurable 特性 |
是 | 否 |
什么时候使用 Object.preventExtensions()
?
- 当你希望对象保持现有属性不变,但允许修改现有属性的值时。
- 例如,你可能希望创建一个配置对象,该对象包含一些默认配置项,你不希望别人添加新的配置项,但允许修改现有配置项的值。
什么时候使用 Object.seal()
?
- 当你希望对象完全保持不变,不允许添加、删除或重新配置属性时。
- 例如,你可能希望创建一个常量对象,该对象包含一些固定的常量值,你不希望别人修改这些常量值,或者添加、删除新的常量。
五、 深入思考:Object.freeze()
的乱入
除了 Object.preventExtensions()
和 Object.seal()
之外,JavaScript还有一个 Object.freeze()
方法,它的作用比 Object.seal()
更加严格。
Object.freeze()
不仅禁止添加、删除和重新配置属性,还禁止修改现有属性的值。也就是说,Object.freeze()
会将对象变成一个真正的“冰冻状态”,任何试图修改对象的操作都会失败。
let obj = {
name: '冻梨',
age: 18
};
Object.freeze(obj);
obj.name = '冰糖葫芦'; // 试图修改属性值
console.log(obj.name); // 输出 '冻梨'
delete obj.age; //试图删除属性
console.log(obj.age); // 输出 18
obj.address = '东北'; //试图增加属性
console.log(obj.address); // 输出 undefined
Object.freeze()
就像把对象封印起来,彻底禁止任何修改。
Object.preventExtensions()
、Object.seal()
和 Object.freeze()
的比较:
特性 | Object.preventExtensions() |
Object.seal() |
Object.freeze() |
---|---|---|---|
禁止添加新属性 | 是 | 是 | 是 |
禁止删除现有属性 | 否 | 是 | 是 |
修改现有属性值 | 是 | 是 | 否 |
修改属性的 configurable 特性 |
是 | 否 | 否 |
修改属性的 writable 特性 |
是 | 是 | 否 (设置为 false ) |
六、 总结与实战
掌握 Object.preventExtensions()
、Object.seal()
和 Object.freeze()
可以帮助我们更好地控制对象的行为,防止对象被意外修改,提高代码的健壮性和安全性。
在实际开发中,我们可以根据具体需求选择合适的保护策略。例如,在开发一个框架或库时,可以使用 Object.freeze()
来保护核心对象,防止用户修改这些对象。或者,在开发一个配置对象时,可以使用 Object.seal()
来防止用户添加或删除配置项,但允许用户修改现有配置项的值。
总之,合理运用 Object.preventExtensions()
、Object.seal()
和 Object.freeze()
,可以让我们的代码更加健壮、安全、可维护。
好了,今天的讲座就到这里,希望大家有所收获! 下课!