Object.freeze()

Object.freeze() 静态方法冻结对象。冻结对象 防止扩展 并使现有属性不可写且不可配置。冻结的对象无法再更改:无法添加新属性,无法删除现有属性,无法更改其可枚举性、可配置性、可写性或值,并且无法重新分配对象的原型。freeze() 返回与传入的对象相同的对象。

¥The Object.freeze() static method freezes an object. Freezing an object prevents extensions and makes existing properties non-writable and non-configurable. A frozen object can no longer be changed: new properties cannot be added, existing properties cannot be removed, their enumerability, configurability, writability, or value cannot be changed, and the object's prototype cannot be re-assigned. freeze() returns the same object that was passed in.

冻结对象是 JavaScript 提供的最高完整性级别。

¥Freezing an object is the highest integrity level that JavaScript provides.

Try it

语法

¥Syntax

js
Object.freeze(obj)

参数

¥Parameters

obj

要冻结的对象。

返回值

¥Return value

传递给函数的对象。

¥The object that was passed to the function.

描述

¥Description

冻结一个对象相当于 防止扩展,然后将所有现有的 properties'descriptors' configurable 更改为 false — 对于数据属性,也将 writable 更改为 false。不能向冻结对象的属性集中添加或删除任何内容。任何这样做的尝试都会失败,要么默默地失败,要么抛出 TypeError 异常(最常见,但不限于,当在 strict mode 中时)。

¥Freezing an object is equivalent to preventing extensions and then changing all existing properties' descriptors' configurable to false — and for data properties, writable to false as well. Nothing can be added to or removed from the properties set of a frozen object. Any attempt to do so will fail, either silently or by throwing a TypeError exception (most commonly, but not exclusively, when in strict mode).

对于冻结对象的数据属性,由于 writableconfigurable 属性设置为 false,因此无法更改其值。访问器属性(getter 和 setter)的工作方式相同 — getter 返回的属性值仍然可能会更改,并且在设置属性时仍然可以调用 setter,而不会引发错误。请注意,作为对象的值仍然可以修改,除非它们也被冻结。作为一个对象,数组可以被冻结;执行此操作后,其元素无法更改,也无法向数组添加或删除任何元素。

¥For data properties of a frozen object, their values cannot be changed since the writable and configurable attributes are set to false. Accessor properties (getters and setters) work the same — the property value returned by the getter may still change, and the setter can still be called without throwing errors when setting the property. Note that values that are objects can still be modified, unless they are also frozen. As an object, an array can be frozen; after doing so, its elements cannot be altered and no elements can be added to or removed from the array.

私有属性 没有属性描述符的概念。冻结具有私有属性的对象并不会阻止这些私有属性的值被更改。(冻结对象通常是针对外部代码的安全措施,但外部代码无论如何都无法访问私有属性。)无论对象是否被冻结,都无法在对象中添加或删除私有属性。

¥Private properties do not have the concept of property descriptors. Freezing an object with private properties does not prevent the values of these private properties from being changed. (Freezing objects is usually meant as a security measure against external code, but external code cannot access private properties anyway.) Private properties cannot be added or removed from the object, whether the object is frozen or not.

freeze() 返回传递给函数的同一对象。它不会创建冻结副本。

¥freeze() returns the same object that was passed into the function. It does not create a frozen copy.

带有元素的 TypedArrayDataView 将导致 TypeError,因为它们是内存视图,并且肯定会导致其他可能的问题:

¥A TypedArray or a DataView with elements will cause a TypeError, as they are views over memory and will definitely cause other possible issues:

js
Object.freeze(new Uint8Array(0)); // No elements
// Uint8Array []

Object.freeze(new Uint8Array(1)); // Has elements
// TypeError: Cannot freeze array buffer views with elements

Object.freeze(new DataView(new ArrayBuffer(32))); // No elements
// DataView {}

Object.freeze(new Float64Array(new ArrayBuffer(64), 63, 0)); // No elements
// Float64Array []

Object.freeze(new Float64Array(new ArrayBuffer(64), 32, 2)); // Has elements
// TypeError: Cannot freeze array buffer views with elements

请注意,由于标准的三个属性(buf.byteLengthbuf.byteOffsetbuf.buffer)是只读的(与 ArrayBufferSharedArrayBuffer 的属性一样),因此没有理由尝试冻结这些属性。

¥Note that as the standard three properties (buf.byteLength, buf.byteOffset and buf.buffer) are read-only (as are those of an ArrayBuffer or SharedArrayBuffer), there is no reason for attempting to freeze these properties.

Object.seal() 不同,使用 Object.freeze() 冻结的对象中的现有属性是不可变的,并且数据属性无法重新分配。

¥Unlike Object.seal(), existing properties in objects frozen with Object.freeze() are made immutable and data properties cannot be re-assigned.

示例

¥Examples

冷冻对象

¥Freezing objects

js
const obj = {
  prop() {},
  foo: "bar",
};

// Before freezing: new properties may be added,
// and existing properties may be changed or removed
obj.foo = "baz";
obj.lumpy = "woof";
delete obj.prop;

// Freeze.
const o = Object.freeze(obj);

// The return value is just the same object we passed in.
o === obj; // true

// The object has become frozen.
Object.isFrozen(obj); // === true

// Now any changes will fail
obj.foo = "quux"; // silently does nothing
// silently doesn't add the property
obj.quaxxor = "the friendly duck";

// In strict mode such attempts will throw TypeErrors
function fail() {
  "use strict";
  obj.foo = "sparky"; // throws a TypeError
  delete obj.foo; // throws a TypeError
  delete obj.quaxxor; // returns true since attribute 'quaxxor' was never added
  obj.sparky = "arf"; // throws a TypeError
}

fail();

// Attempted changes through Object.defineProperty;
// both statements below throw a TypeError.
Object.defineProperty(obj, "ohai", { value: 17 });
Object.defineProperty(obj, "foo", { value: "eit" });

// It's also impossible to change the prototype
// both statements below will throw a TypeError.
Object.setPrototypeOf(obj, { x: 20 });
obj.__proto__ = { x: 20 };

冻结数组

¥Freezing arrays

js
const a = [0];
Object.freeze(a); // The array cannot be modified now.

a[0] = 1; // fails silently

// In strict mode such attempt will throw a TypeError
function fail() {
  "use strict";
  a[0] = 1;
}

fail();

// Attempted to push
a.push(2); // throws a TypeError

被冻结的对象是不可变的。然而,它不一定是恒定的。以下示例显示冻结的对象不是恒定的(冻结是浅的)。

¥The object being frozen is immutable. However, it is not necessarily constant. The following example shows that a frozen object is not constant (freeze is shallow).

js
const obj1 = {
  internal: {},
};

Object.freeze(obj1);
obj1.internal.a = "aValue";

obj1.internal.a; // 'aValue'

要成为常量对象,整个引用图(对其他对象的直接和间接引用)必须仅引用不可变的冻结对象。被冻结的对象被认为是不可变的,因为整个对象内的整个对象状态(值和对其他对象的引用)是固定的。请注意,字符串、数字和布尔值始终是不可变的,并且函数和数组是对象。

¥To be a constant object, the entire reference graph (direct and indirect references to other objects) must reference only immutable frozen objects. The object being frozen is said to be immutable because the entire object state (values and references to other objects) within the whole object is fixed. Note that strings, numbers, and booleans are always immutable and that Functions and Arrays are objects.

"浅冻结" 是什么?

¥What is "shallow freeze"?

调用 Object.freeze(object) 的结果仅适用于 object 本身的直接属性,并且将阻止将来仅在 object 上进行属性添加、删除或值重新分配操作。如果这些属性的值是对象本身,则这些对象不会被冻结,并且可能是属性添加、删除或值重新分配操作的目标。

¥The result of calling Object.freeze(object) only applies to the immediate properties of object itself and will prevent future property addition, removal or value re-assignment operations only on object. If the value of those properties are objects themselves, those objects are not frozen and may be the target of property addition, removal or value re-assignment operations.

js
const employee = {
  name: "Mayank",
  designation: "Developer",
  address: {
    street: "Rohini",
    city: "Delhi",
  },
};

Object.freeze(employee);

employee.name = "Dummy"; // fails silently in non-strict mode
employee.address.city = "Noida"; // attributes of child object can be modified

console.log(employee.address.city); // "Noida"

要使对象不可变,请递归地冻结每个非原始属性(深度冻结)。当你知道对象在参考图中不包含 cycles 时,请根据你的设计具体情况使用该模式,否则将触发无限循环。对 deepFreeze() 的增强是拥有一个接收路径(例如数组)参数的内部函数,这样当对象处于不可变的过程中时,你可以抑制递归调用 deepFreeze()。你仍然面临冻结不应冻结的对象的风险,例如 window

¥To make an object immutable, recursively freeze each non-primitive property (deep freeze). Use the pattern on a case-by-case basis based on your design when you know the object contains no cycles in the reference graph, otherwise an endless loop will be triggered. An enhancement to deepFreeze() would be to have an internal function that receives a path (e.g. an Array) argument so you can suppress calling deepFreeze() recursively when an object is in the process of being made immutable. You still run a risk of freezing an object that shouldn't be frozen, such as window.

js
function deepFreeze(object) {
  // Retrieve the property names defined on object
  const propNames = Reflect.ownKeys(object);

  // Freeze properties before freezing self
  for (const name of propNames) {
    const value = object[name];

    if ((value && typeof value === "object") || typeof value === "function") {
      deepFreeze(value);
    }
  }

  return Object.freeze(object);
}

const obj2 = {
  internal: {
    a: null,
  },
};

deepFreeze(obj2);

obj2.internal.a = "anotherValue"; // fails silently in non-strict mode
obj2.internal.a; // null

规范

Specification
ECMAScript Language Specification
# sec-object.freeze

¥Specifications

浏览器兼容性

BCD tables only load in the browser

¥Browser compatibility

也可以看看