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
语法
参数
返回值
描述
¥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).
对于冻结对象的数据属性,由于 writable
和 configurable
属性设置为 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.
带有元素的 TypedArray
或 DataView
将导致 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:
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.byteLength
、buf.byteOffset
和 buf.buffer
)是只读的(与 ArrayBuffer
或 SharedArrayBuffer
的属性一样),因此没有理由尝试冻结这些属性。
¥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.
示例
冷冻对象
¥Freezing objects
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
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).
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.
深度冻结
¥Deep freezing
调用 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.
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 时,请根据你的设计具体情况使用该模式,否则将触发无限循环。例如,使用 function
语法创建的函数具有 prototype
属性和指向函数本身的 constructor
属性,因此默认情况下它们具有循环。其他功能(例如 箭头函数)仍然可以冻结。
¥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. For example, functions created with the function
syntax have a prototype
property with a constructor
property that points to the function itself, so they have cycles by default. Other functions, such as arrow functions, can still be frozen.
deepFreeze()
的增强功能是存储它已经访问过的对象,因此当对象处于不可变的过程中时,你可以抑制递归调用 deepFreeze()
。例如,请参阅 使用 WeakSet
检测循环引用。你仍然面临冻结不应冻结的对象的风险,例如 window
。
¥An enhancement to deepFreeze()
would be to store the objects it has already visited, so you can suppress calling deepFreeze()
recursively when an object is in the process of being made immutable. For one example, see using WeakSet
to detect circular references. You still run a risk of freezing an object that shouldn't be frozen, such as window
.
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 |
浏览器兼容性
BCD tables only load in the browser