发布于 2026-01-06 1 阅读
0

Javascript 中的 Object.freeze 与 Object.seal 的区别

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);
Enter fullscreen mode Exit fullscreen mode

`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";
Enter fullscreen mode Exit fullscreen mode

根据我刚才的描述,你应该能猜出这个物体现在的样子了:

console.log(objectToFreeze)

// objectToFreeze :
{ age: 28,
  name: 'Damien',
  pets: [ 'Symba', 'Hades', 'Kiwi', 'Grenade' ],
  sibling: {
    age: 26,
    name: 'Corentin'
  }
}
Enter fullscreen mode Exit fullscreen mode

删除操作失败,修改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;
Enter fullscreen mode Exit fullscreen mode

抛出这个:

TypeError 对象冻结

浅冻

当我们调用`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);
};
Enter fullscreen mode Exit fullscreen mode

让我们把它应用到第一个对象上:

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
Enter fullscreen mode Exit fullscreen mode

太好了!现在,我们的兄弟对象和宠物数组都无法被修改了。

对象已冻结

要知道一个对象是否被冻结,可以使用Object.isFrozen()

Object.isFrozen(objectToFreeze); // === true

let unfrozenObj = { a: 42 };
Object.isFrozen(unfrozenObj); // === false
Enter fullscreen mode Exit fullscreen mode

对象.密封件

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);
Enter fullscreen mode Exit fullscreen mode

很简单吧?现在我们来尝试修改这个对象:

delete objectToSeal.name;
objectToSeal.age = 56;
objectToSeal.lastName = "Cosset";
objectToSeal.sibling.age = 45;
objectToSeal.pets.push("Grenade");
Enter fullscreen mode Exit fullscreen mode

或许你已经猜到接下来会发生什么了😉

//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!
Enter fullscreen mode Exit fullscreen mode

请注意,与Object.freeze一样Object.seal在非严格模式下会静默失败,而在严格模式下会抛出 TypeError。

对象已密封

我们还有一种方法来判断一个对象是否被密封。非常明确,我们可以调用Object.isSealed来知道:

Object.isSealed(objectToSeal); // === true

let notSealedObj = { a: 54 };
Object.isSealed(notSealedObj); // === false
Enter fullscreen mode Exit fullscreen mode

如果是 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})

Enter fullscreen mode Exit fullscreen mode

`setPrototypeOf`用于更改对象的原型。当对象被密封或冻结时,您将无法执行此操作。与往常一样,在非严格模式下,此操作将静默失败。在严格模式下,您会看到一个错误信息。TypeError: Object is not extensible.

结论

了解Object.freezeObject.seal之间的区别非常重要。意识到这些区别可以避免你在代码中使用它们时遇到一些问题。

总结一下:

图示总结了 Object.freeze 和 Object.seal 之间的区别。

文章来源:https://dev.to/damcosset/object-freeze-vs-object-seal-in-javascript-3kob