1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
|
---
title: Object.freeze()
slug: Web/JavaScript/Reference/Global_Objects/Object/freeze
tags:
- ECMAScript 5
- JavaScript
- Method
- Object
translation_of: Web/JavaScript/Reference/Global_Objects/Object/freeze
---
<div>{{JSRef}}</div>
<p><strong><code>Object.freeze()</code></strong> 方法可以<strong>冻结</strong>一个对象。一个被冻结的对象再也不能被修改;冻结了一个对象则不能向这个对象添加新的属性,不能删除已有属性,不能修改该对象已有属性的可枚举性、可配置性、可写性,以及不能修改已有属性的值。此外,冻结一个对象后该对象的原型也不能被修改。<code>freeze()</code> 返回和传入的参数相同的对象。</p>
<div>{{EmbedInteractiveExample("pages/js/object-freeze.html")}}</div>
<h2 id="Syntax">语法</h2>
<pre class="syntaxbox"><code>Object.freeze(<em>obj</em>)</code></pre>
<h3 id="Parameters">参数</h3>
<dl>
<dt><code>obj</code></dt>
<dd>要被冻结的对象。</dd>
</dl>
<h3 id="返回值">返回值</h3>
<p>被冻结的对象。</p>
<h2 id="Description">描述</h2>
<p>被冻结对象自身的所有属性都不可能以任何方式被修改。任何修改尝试都会失败,无论是静默地还是通过抛出{{jsxref("TypeError")}}异常(最常见但不仅限于{{jsxref("Strict_mode", "strict mode", "", 1)}})。</p>
<p>数据属性的值不可更改,访问器属性(有getter和setter)也同样(但由于是函数调用,给人的错觉是还是可以修改这个属性)。如果一个属性的值是个对象,则这个对象中的属性是可以修改的,除非它也是个冻结对象。数组作为一种对象,被冻结,其元素不能被修改。没有数组元素可以被添加或移除。</p>
<p>这个方法返回传递的对象,而不是创建一个被冻结的副本。</p>
<h2 id="Examples">例子</h2>
<h3 id="冻结对象">冻结对象</h3>
<pre class="brush: js">var obj = {
prop: function() {},
foo: 'bar'
};
// 新的属性会被添加, 已存在的属性可能
// 会被修改或移除
obj.foo = 'baz';
obj.lumpy = 'woof';
delete obj.prop;
// 作为参数传递的对象与返回的对象都被冻结
// 所以不必保存返回的对象(因为两个对象全等)
var o = Object.freeze(obj);
o === obj; // true
Object.isFrozen(obj); // === true
// 现在任何改变都会失效
obj.foo = 'quux'; // 静默地不做任何事
// 静默地不添加此属性
obj.quaxxor = 'the friendly duck';
// 在严格模式,如此行为将抛出 TypeErrors
function fail(){
'use strict';
obj.foo = 'sparky'; // throws a TypeError
delete obj.quaxxor; // 返回true,因为quaxxor属性从来未被添加
obj.sparky = 'arf'; // throws a TypeError
}
fail();
// 试图通过 Object.defineProperty 更改属性
// 下面两个语句都会抛出 TypeError.
Object.defineProperty(obj, 'ohai', { value: 17 });
Object.defineProperty(obj, 'foo', { value: 'eit' });
// 也不能更改原型
// 下面两个语句都会抛出 TypeError.
Object.setPrototypeOf(obj, { x: 20 })
obj.__proto__ = { x: 20 }</pre>
<h3 id="冻结数组">冻结数组</h3>
<pre class="brush: js">let a = [0];
Object.freeze(a); // 现在数组不能被修改了.
a[0]=1; // fails silently
a.push(2); // fails silently
// In strict mode such attempts will throw TypeErrors
function fail() {
"use strict"
a[0] = 1;
a.push(2);
}
fail();</pre>
<p>被冻结的对象是不可变的。但也不总是这样。下例展示了冻结对象不是常量对象(浅冻结)。</p>
<pre class="brush: js">obj1 = {
internal: {}
};
Object.freeze(obj1);
obj1.internal.a = 'aValue';
obj1.internal.a // 'aValue'
</pre>
<p>对于一个常量对象,整个引用图(直接和间接引用其他对象)只能引用不可变的冻结对象。冻结的对象被认为是不可变的,因为整个对象中的整个对象状态(对其他对象的值和引用)是固定的。注意,字符串,数字和布尔总是不可变的,而函数和数组是对象。</p>
<p>要使对象不可变,需要递归冻结每个类型为对象的属性(深冻结)。当你知道对象在引用图中不包含任何 <em><a href="https://en.wikipedia.org/wiki/Cycle_(graph_theory)">环</a> </em>(循环引用)时,将根据你的设计逐个使用该模式,否则将触发无限循环。对 deepFreeze() 的增强将是具有接收路径(例如Array)参数的内部函数,以便当对象进入不变时,可以递归地调用 deepFreeze() 。你仍然有冻结不应冻结的对象的风险,例如[window]。</p>
<pre class="brush: js">// 深冻结函数.
function deepFreeze(obj) {
// 取回定义在obj上的属性名
var propNames = Object.getOwnPropertyNames(obj);
// 在冻结自身之前冻结属性
propNames.forEach(function(name) {
var prop = obj[name];
// 如果prop是个对象,冻结它
if (typeof prop == 'object' && prop !== null)
deepFreeze(prop);
});
// 冻结自身(no-op if already frozen)
return Object.freeze(obj);
}
obj2 = {
internal: {}
};
deepFreeze(obj2);
obj2.internal.a = 'anotherValue';
obj2.internal.a; // undefined
</pre>
<h2 id="Notes">Notes</h2>
<p>在ES5中,如果这个方法的参数不是一个对象(一个原始值),那么它会导致 {{jsxref("TypeError")}}。在ES2015中,非对象参数将被视为要被冻结的普通对象,并被简单地返回。</p>
<pre class="brush: js">> Object.freeze(1)
TypeError: 1 is not an object // ES5 code
> Object.freeze(1)
1 // ES2015 code</pre>
<h3 id="对比_Object.seal()">对比 <code>Object.seal()</code></h3>
<p>用<code>Object.seal()</code>密封的对象可以改变它们现有的属性。使用<code>Object.freeze()</code> 冻结的对象中现有属性是不可变的。</p>
<h2 id="规范">规范</h2>
<table class="standard-table">
<tbody>
<tr>
<th scope="col">Specification</th>
<th scope="col">Status</th>
<th scope="col">Comment</th>
</tr>
<tr>
<td>{{SpecName('ES5.1', '#sec-15.2.3.9', 'Object.freeze')}}</td>
<td>{{Spec2('ES5.1')}}</td>
<td>Initial definition.<br>
Implemented in JavaScript 1.8.5</td>
</tr>
<tr>
<td>{{SpecName('ES6', '#sec-object.freeze', 'Object.freeze')}}</td>
<td>{{Spec2('ES6')}}</td>
<td> </td>
</tr>
<tr>
<td>{{SpecName('ESDraft', '#sec-object.freeze', 'Object.freeze')}}</td>
<td>{{Spec2('ESDraft')}}</td>
<td> </td>
</tr>
</tbody>
</table>
<h2 id="浏览器兼容性">浏览器兼容性</h2>
<p>{{Compat("javascript.builtins.Object.freeze")}}</p>
<h2 id="See_also">相关链接</h2>
<ul>
<li>{{jsxref("Object.isFrozen")}}</li>
<li>{{jsxref("Object.preventExtensions")}}</li>
<li>{{jsxref("Object.isExtensible")}}</li>
<li>{{jsxref("Object.seal")}}</li>
<li>{{jsxref("Object.isSealed")}}</li>
</ul>
|