对象初始化器
对象初始化器是一个由零个或多个属性名及其关联值的对组成的、用逗号分隔的列表,用花括号 ({}) 括起来。对象也可以使用 Object.create() 或 通过使用 new 操作符调用构造函数 来初始化。
试一试
const object1 = { a: "foo", b: 42, c: {} };
console.log(object1.a);
// Expected output: "foo"
const a = "foo";
const b = 42;
const c = {};
const object2 = { a: a, b: b, c: c };
console.log(object2.b);
// Expected output: 42
const object3 = { a, b, c };
console.log(object3.a);
// Expected output: "foo"
语法
o = {
a: "foo",
b: 42,
c: {},
1: "number literal property",
"foo:bar": "string literal property",
shorthandProperty,
method(parameters) {
// …
},
get property() {},
set property(value) {},
[expression]: "computed property",
__proto__: prototype,
...spreadProperty,
};
描述
对象初始化器是描述 Object 初始化的表达式。对象由用于描述对象的“属性”组成。对象属性的值可以包含原始数据类型或其他对象。
对象字面量语法 vs. JSON
对象字面量语法与 JavaScript Object Notation (JSON) 不同。尽管它们看起来相似,但它们之间存在差异。
- JSON“只”允许使用
"property": value语法定义属性。属性名必须用双引号括起来,并且定义不能是简写形式。也不允许使用计算属性名。 - JSON 对象属性值只能是字符串、数字、
true、false、null、数组或另一个 JSON 对象。这意味着 JSON 不能表示方法或非普通对象,例如Map或RegExp。 - 在 JSON 中,
"__proto__"是一个普通的属性键。在对象字面量中,它设置了对象的原型。
JSON 是对象字面量语法的“严格子集”,这意味着每个有效的 JSON 文本都可以被解析为对象字面量,并且很可能不会导致语法错误。唯一的例外是对象字面量语法禁止重复的 __proto__ 键,这不适用于 JSON.parse()。后者将 __proto__ 视为普通属性,并取最后一次出现的作为属性值。它们所代表的对象值(即它们的语义)唯一不同的时候是源包含 __proto__ 键的时候——对于对象字面量,它设置对象的原型;对于 JSON,它是一个普通属性。
console.log(JSON.parse('{ "__proto__": 0, "__proto__": 1 }')); // {__proto__: 1}
console.log({ "__proto__": 0, "__proto__": 1 }); // SyntaxError: Duplicate __proto__ fields are not allowed in object literals
console.log(JSON.parse('{ "__proto__": {} }')); // { __proto__: {} }
console.log({ "__proto__": {} }); // {} (with {} as prototype)
示例
创建对象
可以像这样创建一个没有属性的空对象
const object = {};
然而,字面量或初始化器表示法的优点是,你可以在花括号内快速创建带有属性的对象。你用逗号分隔的 key: value 对列表表示。
以下代码创建了一个具有三个属性的对象,键分别为 "foo"、"age" 和 "baz"。这些键的值分别为字符串 "bar"、数字 42 和另一个对象。
const object = {
foo: "bar",
age: 42,
baz: { myProp: 12 },
};
访问属性
一旦创建了对象,你可能想要读取或更改它们。可以使用点表示法或方括号表示法来访问对象属性。(有关详细信息,请参阅属性访问器。)
object.foo; // "bar"
object["age"]; // 42
object.baz; // {myProp: 12}
object.baz.myProp; // 12
属性定义
我们已经学习了如何使用初始化器语法来表示属性。通常,你的代码中有一些变量,你希望将它们放入对象中。你会看到这样的代码
const a = "foo";
const b = 42;
const c = {};
const o = {
a: a,
b: b,
c: c,
};
有一种更短的表示法可以实现相同的目的
const a = "foo";
const b = 42;
const c = {};
// Shorthand property names
const o = { a, b, c };
// In other words,
console.log(o.a === { a }.a); // true
重复的属性名
当对属性使用相同的名称时,第二个属性将覆盖第一个属性。
const a = { x: 1, x: 2 };
console.log(a); // {x: 2}
ES2015 之后,在任何地方都允许重复的属性名,包括严格模式。你也可以在类中拥有重复的属性名。唯一的例外是私有元素,它们在类体中必须是唯一的。
方法定义
const o = {
property: function (parameters) {},
get property() {
return 1;
},
set property(value) {},
};
可以使用简写符号,这样就不再需要 function 关键字。
// Shorthand method names
const o = {
property(parameters) {},
};
还有一种简洁地定义生成器方法的方法。
const o = {
*generator() {
// …
},
};
这等同于这种类似 ES5 的表示法(但请注意 ECMAScript 5 没有生成器)
const o = {
generator: function* () {
// …
},
};
有关方法的更多信息和示例,请参阅方法定义。
计算属性名
对象初始化器语法还支持计算属性名。这允许你在方括号 [] 中放置一个表达式,该表达式将被计算并用作属性名。这让人联想到属性访问器语法的方括号表示法,你可能已经用它来读取和设置属性。
现在你也可以在对象字面量中使用类似的语法了
// Computed property names
let i = 0;
const 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
const items = ["A", "B", "C"];
const obj = {
[items]: "Hello",
};
console.log(obj); // A,B,C: "Hello"
console.log(obj["A,B,C"]); // "Hello"
const param = "size";
const config = {
[param]: 12,
[`mobile${param.charAt(0).toUpperCase()}${param.slice(1)}`]: 4,
};
console.log(config); // {size: 12, mobileSize: 4}
扩展属性
对象字面量支持扩展语法。它将给定对象的可枚举自有属性复制到新对象上。
现在可以使用比 Object.assign() 更短的语法来实现浅克隆(不包括 prototype)或合并对象。
const obj1 = { foo: "bar", x: 42 };
const obj2 = { foo: "baz", y: 13 };
const clonedObj = { ...obj1 };
// { foo: "bar", x: 42 }
const mergedObj = { ...obj1, ...obj2 };
// { foo: "baz", x: 42, y: 13 }
警告:请注意,Object.assign() 会触发设置器,而扩展语法不会!
原型设置器
形式为 __proto__: value 或 "__proto__": value 的属性定义不会创建名为 __proto__ 的属性。相反,如果提供的值是一个对象或 null,它会将创建的对象的 [[Prototype]] 指向该值。(如果该值不是对象或 null,则对象不会改变。)
请注意,__proto__ 键是标准化语法,与非标准且性能不佳的 Object.prototype.__proto__ 访问器形成对比。它在对象创建期间设置 [[Prototype]],类似于 Object.create——而不是改变原型链。
const obj1 = {};
console.log(Object.getPrototypeOf(obj1) === Object.prototype); // true
const obj2 = { __proto__: null };
console.log(Object.getPrototypeOf(obj2)); // null
const protoObj = {};
const obj3 = { "__proto__": protoObj };
console.log(Object.getPrototypeOf(obj3) === protoObj); // true
const obj4 = { __proto__: "not an object or null" };
console.log(Object.getPrototypeOf(obj4) === Object.prototype); // true
console.log(Object.hasOwn(obj4, "__proto__")); // false
对象字面量中只允许一个原型设置器。多个原型设置器会导致语法错误。
不使用“冒号”表示法的属性定义不是原型设置器。它们是属性定义,其行为与使用任何其他名称的类似定义相同。
const __proto__ = "variable";
const obj1 = { __proto__ };
console.log(Object.getPrototypeOf(obj1) === Object.prototype); // true
console.log(Object.hasOwn(obj1, "__proto__")); // true
console.log(obj1.__proto__); // "variable"
const obj2 = { __proto__() { return "hello"; } };
console.log(obj2.__proto__()); // "hello"
const obj3 = { ["__proto__"]: 17 };
console.log(obj3.__proto__); // 17
// Mixing prototype setter with normal own properties with "__proto__" key
const obj4 = { ["__proto__"]: 17, __proto__: {} }; // {__proto__: 17} (with {} as prototype)
const obj5 = {
["__proto__"]: 17,
__proto__: {},
__proto__: null, // SyntaxError: Duplicate __proto__ fields are not allowed in object literals
};
const obj6 = {
["__proto__"]: 17,
["__proto__"]: "hello",
__proto__: null,
}; // {__proto__: "hello"} (with null as prototype)
const obj7 = {
["__proto__"]: 17,
__proto__,
__proto__: null,
}; // {__proto__: "variable"} (with null as prototype)
规范
| 规范 |
|---|
| ECMAScript® 2026 语言规范 # sec-object-initializer |
浏览器兼容性
加载中…