JavaScript中的bject.defineProperty()和Object.freeze()方法

JavaScript中的bject.defineProperty()和Object.freeze()方法

为了更好的理解Object.defineProperty()和Object.freeze()方法,先回顾一下JavaScript中的常量。

JavaScript常量

在JavaScript中,const关键字用于声明常量,并且也必须在声明时初始化。如果尝试声明一个const常量而不初始化,将会导致一个语法错误。换言之,在JavaScript中,使用const关键字声明的变量是不能被重新赋值的,这意味着它们的值在初始化后不能被改变。下面是一个例子:

const MAX_VALUE = 100;

MAX_VALUE = 200; // 这会抛出一个运行时错误

如果你尝试运行上面的代码,JavaScript会抛出一个错误,因为你试图给一个用const声明的常量重新赋值。

然而,当使用const声明一个对象时,对象的属性值是可以被修改的,因为const仅保证变量名指向的引用不会改变,而不是对象内容的不变性。例如:

const MY_OBJECT = { key: "initial value" };

MY_OBJECT.key = "new value"; // 这是允许的

在上面的例子中,尽管MY_OBJECT是一个常量,我们仍然可以改变它的key属性。

为了创建一个真正不可变的对象,可以使用Object.freeze()方法,或者使用Object.defineProperty()来定义一个不可写的属性。

Object.defineProperty()方法

Object.defineProperty() 是 JavaScript 中用于定义或修改对象属性的方法。使用这个方法,你可以精确地控制属性的特性,例如可枚举性、可配置性、可写性等。Object.defineProperty() - JavaScript | MDN

下面是一个简单的示例:

使用Object.defineProperty()来定义一个不可写的属性。这里是一个使用Object.defineProperty()的例子:

const MAX_VALUE = {};
Object.defineProperty(MAX_VALUE, "value", {
  value: 100,
  writable: false, // 不能写入
  enumerable: true, // 可枚举
  configurable: false // 不能配置
});

MAX_VALUE.value = 200; // 这不会有任何效果,因为属性是不可写的

在上面的代码中,MAX_VALUE对象的value属性被设置为不可写,所以尝试修改它将不会有任何效果。这样,你就能在JavaScript中创建一个真正的常量属性。但请注意,Object.defineProperty()是针对对象属性的,而不是变量本身。如果你需要一个不可变的复杂数据结构,你可能需要对对象中的每个属性都使用Object.defineProperty()。

请注意,Object.defineProperty()是针对对象属性的,而不是变量本身。

Object.freeze() 方法

Object.freeze() 方法可以冻结一个对象,这意味着你不能再给这个对象添加新的属性,不能删除已有的属性,也不能修改已有属性的可枚举性、可配置性、可写性,以及不能修改已有属性的值。被冻结的对象是一个不可变的常量对象。Object.freeze() - JavaScript | MDN

下面是一个使用 Object.freeze() 方法的例子:

const MY_OBJECT = {
  key: "initial value"
};

// 冻结对象
Object.freeze(MY_OBJECT);

// 尝试修改对象的属性
MY_OBJECT.key = "new value"; // 这不会有任何效果,因为对象被冻结了

// 尝试添加新的属性
MY_OBJECT.newKey = "new value"; // 这也不会有任何效果

// 尝试删除属性
delete MY_OBJECT.key; // 这不会有任何效果

console.log(MY_OBJECT); // 输出: { key: "initial value" }

在上面的代码中,尽管我们尝试修改了 MY_OBJECT 的属性、添加新属性和删除属性,但是由于对象已经被 Object.freeze() 冻结,这些操作都不会对对象产生任何影响。

需要注意的是,Object.freeze() 只能冻结对象的直接属性,如果对象的属性值是另一个对象,那么这个嵌套对象的属性仍然是可以被修改的。如果你需要深度冻结一个对象(即冻结对象及其所有嵌套对象),你需要递归地使用 Object.freeze()。下面是一个深度冻结的例子:

function deepFreeze(object) {
  // 取得对象的属性名
  const propNames = Object.getOwnPropertyNames(object);

  // 在冻结自身之前,先冻结每个属性
  propNames.forEach(function(name) {
    const prop = object[name];

    // 如果属性是对象或数组,则递归冻结
    if (typeof prop == 'object' && prop !== null) {
      deepFreeze(prop);
    }
  });

  // 冻结自身 (无法修改、删除、添加属性)
  return Object.freeze(object);
}

const MY_COMPLEX_OBJECT = {
  subObject: {
    key: "value"
  }
};

// 深度冻结对象
deepFreeze(MY_COMPLEX_OBJECT);

// 尝试修改嵌套对象的属性
MY_COMPLEX_OBJECT.subObject.key = "new value"; // 这不会有任何效果

console.log(MY_COMPLEX_OBJECT); // 输出: { subObject: { key: "value" } }

在这个例子中,deepFreeze 函数递归地冻结了 MY_COMPLEX_OBJECT 中的所有对象,包括嵌套的 subObject 对象。因此,尝试修改嵌套对象的属性也不会有任何效果。

猜你喜欢

转载自blog.csdn.net/cnds123/article/details/134807705