Javascript 中的 Object.freeze 与 Object.seal 的区别
对象冻结
以下是如何使用Object.freeze:
let objectToFreeze = {
age: 28,
name: "Damien",
pets: ["Symba", "Hades", "Kiwi"],
sibling: {
age: 25,
name: "Corentin",
},
};
Object.freeze(objectToFreeze);
`Object.freeze` 方法接受一个对象作为参数。请注意,它会修改您传递的参数对象,而不是复制该对象并创建一个新对象。
那么,这对物体来说意味着什么呢?
- 您无法向对象添加新属性。
- 如果属性本身不是对象或数组,则无法对其进行修改。(稍后会详细介绍)
- 您无法从对象中删除属性。
let objectToFreeze = {
age: 28,
name: "Damien",
pets: ["Symba", "Hades", "Kiwi"],
sibling: {
age: 25,
name: "Corentin",
},
};
Object.freeze(objectToFreeze);
delete objectToFreeze.age;
objectToFreeze.name = "Ben";
objectToFreeze.pets.push("Grenade");
objectToFreeze.sibling.age = 26;
objectToFreeze.lastName = "Cosset";
根据我刚才的描述,你应该能猜出这个物体现在的样子了:
console.log(objectToFreeze)
// objectToFreeze :
{ age: 28,
name: 'Damien',
pets: [ 'Symba', 'Hades', 'Kiwi', 'Grenade' ],
sibling: {
age: 26,
name: 'Corentin'
}
}
删除操作失败,修改name属性失败,添加lastName属性也失败。但修改数组及其嵌套的同级对象却成功了。
注意:如果您未使用严格模式,则程序将静默失败。在严格模式下,您将收到类型错误。
"use strict";
let objectToFreeze = {
age: 28,
name: "Damien",
pets: ["Symba", "Hades", "Kiwi"],
sibling: {
age: 25,
name: "Corentin",
},
};
Object.freeze(objectToFreeze);
delete objectToFreeze.age;
抛出这个:
浅冻
当我们调用`Object.freeze`时,我们执行的是浅冻结。我们只会冻结直接附加到对象上的内容。对象内部的属性和数组不受影响。
要使整个对象及其内部所有元素都变为不可变,您需要对每个元素调用`Object.freeze()`方法。以下是一种实现方法:
let allYouCanFreeze = (obj) => {
// Retrieve the properties names
let propNames = Object.getOwnPropertyNames(obj);
// Loop through the properties
// If typeof is "object", meaning an array or object, use recursion to freeze its contents.
for (let name of propNames) {
let value = obj[name];
obj[name] =
value && typeof value === "object" ? allYouCanFreeze(value) : value;
}
// Finally, freeze the main object
return Object.freeze(obj);
};
让我们把它应用到第一个对象上:
let objectToFreeze = {
age: 28,
name: "Damien",
pets: ["Symba", "Hades", "Kiwi"],
sibling: {
age: 25,
name: "Corentin",
},
};
allYouCanFreeze(objectToFreeze);
// Now we can't touch the pets array and the sibling object
objectToFreeze.age = 26; // Now, fails.
objectToFreeze.pets.push("Grenade"); // Now, fails
太好了!现在,我们的兄弟对象和宠物数组都无法被修改了。
对象已冻结
要知道一个对象是否被冻结,可以使用Object.isFrozen():
Object.isFrozen(objectToFreeze); // === true
let unfrozenObj = { a: 42 };
Object.isFrozen(unfrozenObj); // === false
对象.密封件
Object.seal ()方法与 freeze 方法类似,都接受一个对象作为参数。Object.seal是Object.freeze的简化版本。
- 您无法向对象中删除或添加元素。
- 您可以修改现有属性。
let objectToSeal = {
name: "Damien",
age: 28,
pets: ["Symba", "Hades", "Kiwi"],
sibling: {
age: 25,
name: "Corentin",
},
};
Object.seal(objectToSeal);
很简单吧?现在我们来尝试修改这个对象:
delete objectToSeal.name;
objectToSeal.age = 56;
objectToSeal.lastName = "Cosset";
objectToSeal.sibling.age = 45;
objectToSeal.pets.push("Grenade");
或许你已经猜到接下来会发生什么了😉
//objectToSeal new contents
{
name: 'Damien',
age: 56, //modifying worked
pets: ['Symba', 'Hades', 'Kiwi', 'Grenade'], // push worked
sibling: {
age: 45, // Modifying worked
name: 'Corentin'
}
}
// adding and deleting failed!
请注意,与Object.freeze一样,Object.seal在非严格模式下会静默失败,而在严格模式下会抛出 TypeError。
对象已密封
我们还有一种方法来判断一个对象是否被密封。非常明确,我们可以调用Object.isSealed来知道:
Object.isSealed(objectToSeal); // === true
let notSealedObj = { a: 54 };
Object.isSealed(notSealedObj); // === false
如果是 const 呢?
你可能会想看看`Object.seal`和` Object.freeze`,并将它们与`const`进行比较。请记住,它们是不同的概念。`Object.freeze`和` Object.seal`作用于对象的值,而`const`作用于绑定。`Object.freeze`使对象不可变。`const`创建不可变的绑定。一旦你给一个变量赋值,就不能再给该绑定赋新值。
原型呢?
最后还有一点需要说明:原型。如果你还不熟悉 JavaScript 原型,我正在写一篇相关的文章。关于`Object.freeze`和`Object.seal`,需要注意的是,一旦原型被冻结或密封,就无法再进行修改。
let freezeThat = {
name: 'Damien'
}
let sealThis = {
age 28
}
Object.freeze(freezeThat)
Object.seal(sealThis)
// These two lines will fail!
Object.setPrototypeOf(freezeThat, {x: 26})
Object.setPrototypeOf(sealThis, {alive: true})
`setPrototypeOf`用于更改对象的原型。当对象被密封或冻结时,您将无法执行此操作。与往常一样,在非严格模式下,此操作将静默失败。在严格模式下,您会看到一个错误信息。TypeError: Object is not extensible.
结论
了解Object.freeze和Object.seal之间的区别非常重要。意识到这些区别可以避免你在代码中使用它们时遇到一些问题。
总结一下:
文章来源:https://dev.to/damcosset/object-freeze-vs-object-seal-in-javascript-3kob

