掌握 JavaScript 中的 Object.freeze() 和 Object.seal():控制对象可变性

JavaScript 中的 Object.freeze 和 Object.seal

在 JavaScript 中使用对象时,控制其可变性对于防止意外更改至关重要。JavaScript 为此提供的两种方法是 **Object.freeze()** 和 **Object.seal()**。了解它们的区别和用例是编写健壮代码的关键。

1. Object.freeze()

`Object.freeze()` 方法使对象**不可变**。这意味着:

  • 无法添加任何新属性。
  • 现有属性无法被修改、删除或重新配置。
  • 该对象实际上已被“冻结”,无法以任何方式改变。
  • 句法:

    Object.freeze(obj);

    例子:

    const obj = { name: "Alice", age: 25 };
    Object.freeze(obj);
    
    obj.age = 30; // Does nothing (strict mode: throws an error)
    obj.gender = "female"; // Does nothing (strict mode: throws an error)
    delete obj.name; // Does nothing (strict mode: throws an error)
    
    console.log(obj); // { name: "Alice", age: 25 }

    用例:

  • 确保对象在整个程序中保持不变,例如配置设置。
  • 检查物体是否被冻结:

    使用 `Object.isFrozen()` 来判断一个对象是否被冻结:

    console.log(Object.isFrozen(obj)); // true

    2. 对象.seal()

    `Object.seal()` 方法限制对对象的修改,但不如 `Object.freeze()` 严格。它允许:

  • 修改现有属性(值可以改变)。
  • 防止添加或删除属性。
  • 句法:

    Object.seal(obj);

    例子:

    const obj = { name: "Bob", age: 30 };
    Object.seal(obj);
    
    obj.age = 35; // Allowed: Existing properties can be modified
    obj.gender = "male"; // Does nothing (strict mode: throws an error)
    delete obj.name; // Does nothing (strict mode: throws an error)
    
    console.log(obj); // { name: "Bob", age: 35 }

    用例:

  • 当您想要保护对象的结构(防止添加/删除)但仍允许更改属性值时。
  • 检查对象是否被密封:

    使用 `Object.isSealed()` 来判断一个对象是否被密封:

    console.log(Object.isSealed(obj)); // true

    3. Object.freeze() 和 Object.seal() 之间的主要区别

    4. 冷冻和密封的嵌套对象

    `Object.freeze()` 和 `Object.seal()` 都是 **浅** 的,这意味着它们不会影响嵌套对象。要深度冻结或密封对象,您需要将该方法递归应用于每个嵌套对象。

    示例(浅层效应):

    const obj = {
      name: "Eve",
      details: { age: 28 }
    };
    
    Object.freeze(obj);
    obj.details.age = 30; // Allowed, as `details` is not frozen
    
    console.log(obj); // { name: "Eve", details: { age: 30 } }

    Deep Freeze 助手功能:

    function deepFreeze(obj) {
      Object.freeze(obj);
      for (const key in obj) {
        if (typeof obj[key] === "object" && obj[key] !== null) {
          deepFreeze(obj[key]);
        }
      }
    }
    
    const obj = {
      name: "Eve",
      details: { age: 28 }
    };
    
    deepFreeze(obj);
    obj.details.age = 30; // Not allowed
    
    console.log(obj); // { name: "Eve", details: { age: 28 } }

    5. 常见陷阱和提示

  • 非严格模式行为:在非严格模式下,对冻结或密封对象的更改会默默失败。始终使用严格模式(“use strict”;)以便更清晰地进行调试。
  • 防止与对象可变性混淆:清楚地记录对象被冻结或密封的时间和原因,以避免在团队环境中产生误解。
  • 冻结前密封:如果想要同时具有受限结构和不变性,请先密封对象,然后冻结它。
  • 结论

    `Object.freeze()` 和 `Object.seal()` 都是用于管理 JavaScript 中对象不变性的有用工具。虽然 `Object.freeze()` 确保完全不变,但 `Object.seal()` 通过允许更改现有属性值提供了灵活性。选择正确的方法取决于您对对象的控制级别。