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
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
|
---
title: 对象初始化
slug: Web/JavaScript/Reference/Operators/Object_initializer
tags:
- ECMAScript 2015
- JavaScript
- Literal
- Methods
- Object
- Primary Expression
- computed
- mutation
- properties
translation_of: Web/JavaScript/Reference/Operators/Object_initializer
---
<div>{{JsSidebar("Operators")}}</div>
<p>可以通过<a href="/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object"><code>new Object()</code></a>,<code> <a href="/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/create">Object.create()</a></code>方法,或者使用字面量标记(初始化标记)初始化对象。 一个对象初始化器,由花括号/大括号 (<code>{}</code>) 包含的一个由零个或多个对象属性名和其关联值组成的一个逗号分隔的列表构成。</p>
<h2 id="语法">语法</h2>
<pre class="brush: js">var o = {};
var o = {a: 'foo', b: 42, c: {}};
var a = 'foo', b = 42, c = {};
var o = {a: a, b: b, c: c};
var o = {
property: function ([parameters]) {},
get property() {},
set property(value) {}
};</pre>
<h3 id="ECMAScript_2015_的新标记">ECMAScript 2015 的新标记</h3>
<p>请参考兼容性表格获取这些标记的支持信息。在不被支持的环境中,这些标记将造成语法错误。</p>
<pre class="brush: js">// Shorthand property names (ES2015)
var a = 'foo', b = 42, c = {};
var o = {a, b, c};
// Shorthand method names (ES2015)
var o = {
property([parameters]) {}
};
// Computed property names (ES2015)
var prop = 'foo';
var o = {
[prop]: 'hey',
['b' + 'ar']: 'there'
};</pre>
<h2 id="描述">描述</h2>
<p>对象初始化是一个描述{{jsxref("Object","对象")}}初始化过程的表达式。对象初始化是由一组描述对象的属性组成。属性的值可以是{{Glossary("primitive","原始")}}类型,也可以是其他对象。</p>
<h3 id="创建对象">创建对象</h3>
<p>没有属性的空对象可以用以下方式创建:</p>
<pre class="brush: js">let obj = {};</pre>
<p>不过,<em>字面 </em>和<em>初始化 </em>标记的优势在于,可以用内含属性的花括号快速创建对象。简单地编写一个逗号分隔的键值对的类别。如下代码创建了一个含三个属性的对象,键分别为 "<code>foo</code>", "<code>age</code>" 和 "<code>baz</code>"。这些键对应的值,分别是字符串“<code>bar</code>”,数字<code>42</code>和另一个对象。</p>
<pre class="brush: js">let obj = {
foo: "bar",
age: 42,
baz: { myProp: 12 },
}</pre>
<h3 id="属性访问">属性访问</h3>
<p>创建对象后,可以读取或者修改它。对象属性可以用下标小圆点标记或者方括号标记访问。参考<a href="/en-US/docs/Web/JavaScript/Reference/Operators/Property_Accessors">属性访问</a> 获取更多信息。</p>
<pre class="brush: js">object.foo; // "bar"
object["age"]; // 42
object.foo = "baz";
</pre>
<h3 id="属性定义">属性定义</h3>
<p>上面学习了如何用初始化标记对象属性。经常能遇到希望将代码中的变量放到对象中的情况。可能遇到如下代码:</p>
<pre class="brush: js">var a = "foo",
b = 42,
c = {};
var o = {
a: a,
b: b,
c: c
};</pre>
<p>在 ECMAScript 2015 中,有更简短的标记可以实现同样的效果:</p>
<pre class="brush: js">var a = 'foo',
b = 42,
c = {};
// Shorthand property names (ES2015)
var o = {a, b, c};
// In other words,
console.log((o.a === {a}.a)); // true</pre>
<h4 id="重复属性名">重复属性名</h4>
<p>属性使用了同样的名称时,后面的属性会覆盖前面的属性。</p>
<pre class="brush: js">var a = {x: 1, x: 2};
console.log(a); // { x: 2}
</pre>
<p>在 ECMAScript 5 严格模式的代码中, 重复的属性名会被当做{{jsxref("SyntaxError")}}。引入计算的属性名以后,属性名会在运行时出现重复。ECMAScript 2015 移除了这个限制。</p>
<pre class="brush: js">function haveES6DuplicatePropertySemantics(){
"use strict";
try {
({ prop: 1, prop: 2 });
// No error thrown, duplicate property names allowed in strict mode
return true;
} catch (e) {
// Error thrown, duplicates prohibited in strict mode
return false;
}
}</pre>
<h3 id="方法定义">方法定义</h3>
<p>对象属性也可以是一个<a href="/en-US/docs/Web/JavaScript/Reference/Functions">函数</a>、<a href="/en-US/docs/Web/JavaScript/Reference/Functions/get">getter</a>、<a href="/en-US/docs/Web/JavaScript/Reference/Functions/set">setter</a>方法。</p>
<pre class="brush: js">var o = {
<var>property: function </var>([<var>parameters</var>]) {},
get <var>property</var>() {},
set <var>property</var>(<var>value</var>) {},
};</pre>
<p>ECMAScript 2015引入了一种简短写法, "function" 关键字也可以丢掉。</p>
<pre class="brush: js">// Shorthand method names (ES6)
var o = {
<var>property</var>([<var>parameters</var>]) {},
get <var>property</var>() {},
set <var>property</var>(<var>value</var>) {},
* <var>generator</var>() {}
};</pre>
<p>ECMAScript 2015 提供了一种简明地定义以生成器函数作为值的属性的方法。</p>
<pre class="brush: js">var o = {
* <var>generator</var>() {
...........
}
};</pre>
<p>ECMAScript 5 中可以这样书写(需要注意的是 ES5 没有生成器):</p>
<pre class="brush: js">var o = {
generator<var>Method: function *</var>() {
...........
}
};</pre>
<p>获取更多信息和范例,请参考 <a href="/en-US/docs/Web/JavaScript/Reference/Functions/Method_definitions">method definitions</a>。</p>
<h3 id="计算属性名">计算属性名</h3>
<p>从ECMAScript 2015开始,对象初始化语法开始支持计算属性名。其允许在[]中放入表达式,计算结果可以当做属性名。这种用法和用方括号访问<a href="/en-US/docs/Web/JavaScript/Reference/Operators/Property_Accessors">属性</a>非常类似,也许你已经用来读取和设置属性了。现在同样的语法也可以用于对象字面值了:</p>
<pre class="brush: js">// Computed property names (ES6)
var i = 0;
var a = {
["foo" + ++i]: i,
["foo" + ++i]: i,
["foo" + ++i]: i
};
console.log(a.foo1); // 1
console.log(a.foo2); // 2
console.log(a.foo3); // 3
var param = 'size';
var config = {
[param]: 12,
["mobile" + param.charAt(0).toUpperCase() + param.slice(1)]: 4
};
console.log(config); // { size: 12, mobileSize: 4 }</pre>
<h3 id="扩展属性">扩展属性</h3>
<p> </p>
<p>ECMAScript 提案(第3阶段)的<a href="https://github.com/tc39/proposal-object-rest-spread">剩余/扩展属性</a>将<a href="/zh-CN/docs/Web/JavaScript/Reference/Operators/Spread_operator">扩展</a>属性添加到对象文字。它将自己提供的对象的枚举属性复制到一个新的对象上。</p>
<p>使用比{{jsxref("Object.assign()")}}更短的语法,可以轻松克隆(不包括原型)或合并对象。</p>
<p> </p>
<pre class="brush: js">var obj1 = { foo: 'bar', x: 42 };
var obj2 = { foo: 'baz', y: 13 };
var clonedObj = { ...obj1 };
// Object { foo: "bar", x: 42 }
var mergedObj = { ...obj1, ...obj2 };
// Object { foo: "baz", x: 42, y: 13 }
</pre>
<p>请注意,{{jsxref("Object.assign()")}}会触发<a href="/zh-CN/docs/Web/JavaScript/Reference/Functions/set">setter</a>,而展开操作符则不会。</p>
<h3 id="变更原型">变更原型</h3>
<p>定义属性为<code>__proto__: 值</code> 或 <code>"__proto__": 值</code> 时,不会创建名为<code>__proto__</code>属性。如果给出的值是对象或者<a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/null"><code>null</code></a>,那么对象的<code>[[Prototype]]</code>会被设置为给出的值。(如果给出的值不是对象也不是null,那么对象的原型不会改变。)</p>
<pre class="brush: js">var obj1 = {};
assert(Object.getPrototypeOf(obj1) === Object.prototype);
var obj2 = { __proto__: null };
assert(Object.getPrototypeOf(obj2) === null);
var protoObj = {};
var obj3 = { "__proto__": protoObj };
assert(Object.getPrototypeOf(obj3) === protoObj);
var obj4 = { __proto__: "not an object or null" };
assert(Object.getPrototypeOf(obj4) === Object.prototype);
assert(!obj4.hasOwnProperty("__proto__"));
</pre>
<p>在对象字面值中,仅有一次变更原型的机会;多次变更原型,会被视为语法错误。</p>
<p>不使用冒号标记的属性定义,不会变更对象的原型;而是和其他具有不同名字的属性一样是普通属性定义。</p>
<pre class="brush: js">var __proto__ = "variable";
var obj1 = { __proto__ };
assert(Object.getPrototypeOf(obj1) === Object.prototype);
assert(obj1.hasOwnProperty("__proto__"));
assert(obj1.__proto__ === "variable");
var obj2 = { __proto__() { return "hello"; } };
assert(obj2.__proto__() === "hello");
var obj3 = { ["__prot" + "o__"]: 17 };
assert(obj3.__proto__ === 17);
</pre>
<h2 id="对象字面量表示法与JSON">对象字面量表示法与JSON</h2>
<p>对象字面量表示法和 <strong>J</strong>ava<strong>S</strong>cript <strong>O</strong>bject <strong>N</strong>otation(<a href="/en-US/docs/Glossary/JSON">JSON</a>)是不同的。虽然他们看起来相似,不同点有:</p>
<ul>
<li>JSON 只允许<code>"property": value</code> syntax形式的属性定义。属性名必须用双引号括起来。且属性定义不允许使用简便写法。</li>
<li>JSON中,属性的值仅允许字符串,数字,数组,<code>true</code>,<code>false</code>,<code>null</code>或其他(JSON)对象。 </li>
<li>JSON中,不允许将值设置为函数。</li>
<li> {{jsxref("Date")}} 等对象,经{{jsxref("JSON.parse()")}}处理后,会变成字符串。</li>
<li>{{jsxref("JSON.parse()")}} 不会处理计算的属性名,会当做错误抛出。</li>
</ul>
<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('ES1')}}</td>
<td>{{Spec2('ES1')}}</td>
<td>initial definition.</td>
</tr>
<tr>
<td>{{SpecName('ES5.1', '#sec-11.1.5', 'Object Initializer')}}</td>
<td>{{Spec2('ES5.1')}}</td>
<td><a href="/en-US/docs/Web/JavaScript/Reference/Functions/get">getter</a> and <a href="/en-US/docs/Web/JavaScript/Reference/Functions/set">setter</a> added.</td>
</tr>
<tr>
<td>{{SpecName('ES2015', '#sec-object-initializer', 'Object Initializer')}}</td>
<td>{{Spec2('ES2015')}}</td>
<td>Shorthand method/property names and computed property names added.</td>
</tr>
<tr>
<td>{{SpecName('ESDraft', '#sec-object-initializer', 'Object Initializer')}}</td>
<td>{{Spec2('ESDraft')}}</td>
<td> </td>
</tr>
<tr>
<td><a href="https://github.com/tc39/proposal-object-rest-spread">Rest/Spread Properties for ECMAScript </a></td>
<td>Draft</td>
<td>Stage 3 draft.</td>
</tr>
</tbody>
</table>
<h2 id="浏览器兼容">浏览器兼容</h2>
<p>{{Compat("javascript.operators.object_initializer")}}</p>
<h2 id="相关链接">相关链接</h2>
<ul>
<li><a href="/zh-CN/docs/Web/JavaScript/Reference/Operators/Property_Accessors">Property accessors</a></li>
<li><code><a href="/zh-CN/docs/Web/JavaScript/Reference/Functions/get">get</a></code> / <code><a href="/en-US/docs/Web/JavaScript/Reference/Functions/set">set</a></code></li>
<li><a href="/zh-CN/docs/Web/JavaScript/Reference/Functions/Method_definitions">Method definitions</a></li>
<li><a href="/zh-CN/docs/Web/JavaScript/Reference/Lexical_grammar">Lexical grammar</a></li>
</ul>
|