对象初始值设定项

对象初始值设定项是一个以逗号分隔的列表,其中包含零对或多对对象的属性名称和关联值,括在大括号 ({}) 中。还可以使用 Object.create()通过调用构造函数new 运算符来初始化对象。

¥An object initializer is a comma-delimited list of zero or more pairs of property names and associated values of an object, enclosed in curly braces ({}). Objects can also be initialized using Object.create() or by invoking a constructor function with the new operator.

Try it

语法

¥Syntax

js
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,
};

描述

¥Description

对象初始值设定项是描述 Object 初始化的表达式。对象由属性组成,属性用于描述对象。对象属性的值可以包含 primitive 数据类型或其他对象。

¥An object initializer is an expression that describes the initialization of an Object. Objects consist of properties, which are used to describe an object. The values of object properties can either contain primitive data types or other objects.

对象字面量语法与 JSON

¥Object literal syntax vs. JSON

对象字面量语法与 JavaScript 对象表示法 (JSON) 不同。尽管它们看起来很相似,但它们之间还是有区别的:

¥The object literal syntax is not the same as the JavaScript Object Notation (JSON). Although they look similar, there are differences between them:

  • JSON 仅允许使用 "property": value 语法定义属性。属性名称必须用双引号引起来,并且定义不能是简写。也不允许计算属性名称。
  • JSON 对象属性值只能是字符串、数字、truefalsenull、数组或其他 JSON 对象。这意味着 JSON 无法表达方法或非普通对象(例如 DateRegExp)。
  • 在 JSON 中,"__proto__" 是普通属性键。在对象字面量中,它是 设置对象的原型

JSON 是对象字面量语法的严格子集,这意味着每个有效的 JSON 文本都可以解析为对象字面量,并且可能不会导致语法错误。唯一的例外是对象字面量语法禁止重复的 __proto__ 键,这不适用于 JSON.parse()。后者将 __proto__ 视为普通属性,并将最后一次出现的值作为该属性的值。它们表示的对象值(也称为它们的语义)唯一不同的时候也是当源包含 __proto__ 键时 — 对于对象字面量,它设置对象的原型;对于 JSON,这是一个普通属性。

¥JSON is a strict subset of the object literal syntax, meaning that every valid JSON text can be parsed as an object literal, and would likely not cause syntax errors. The only exception is that the object literal syntax prohibits duplicate __proto__ keys, which does not apply to JSON.parse(). The latter treats __proto__ like a normal property and takes the last occurrence as the property's value. The only time when the object value they represent (a.k.a. their semantic) differ is also when the source contains the __proto__ key — for object literals, it sets the object's prototype; for JSON, it's a normal property.

js
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)

示例

¥Examples

创建对象

¥Creating objects

可以像这样创建一个没有属性的空对象:

¥An empty object with no properties can be created like this:

js
const object = {};

但是,文字或初始值设定项表示法的优点是,你能够快速创建具有大括号内的属性的对象。你记下以逗号分隔的 key: value 对列表。

¥However, the advantage of the literal or initializer notation is, that you are able to quickly create objects with properties inside the curly braces. You notate a list of key: value pairs delimited by commas.

以下代码创建一个具有三个属性的对象,键为 "foo""age""baz"。这些键的值是字符串 "bar"、数字 42 和另一个对象。

¥The following code creates an object with three properties and the keys are "foo", "age" and "baz". The values of these keys are a string "bar", the number 42, and another object.

js
const object = {
  foo: "bar",
  age: 42,
  baz: { myProp: 12 },
};

访问属性

¥Accessing properties

创建对象后,你可能想要读取或更改它们。可以使用点符号或方括号符号来访问对象属性。(详细信息参见 属性访问器。)

¥Once you have created an object, you might want to read or change them. Object properties can be accessed by using the dot notation or the bracket notation. (See property accessors for detailed information.)

js
object.foo; // "bar"
object["age"]; // 42
object.baz; // {myProp: 12}
object.baz.myProp; //12

属性定义

¥Property definitions

我们已经学习了如何使用初始化语法来表示属性。通常,你希望将代码中的变量放入对象中。你会看到这样的代码:

¥We have already learned how to notate properties using the initializer syntax. Oftentimes, there are variables in your code that you would like to put into an object. You will see code like this:

js
const a = "foo";
const b = 42;
const c = {};

const o = {
  a: a,
  b: b,
  c: c,
};

有一个更短的符号可以实现相同的目的:

¥There is a shorter notation available to achieve the same:

js
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

重复的属性名称

¥Duplicate property names

当你的属性使用相同的名称时,第二个属性将覆盖第一个属性。

¥When using the same name for your properties, the second property will overwrite the first.

js
const a = { x: 1, x: 2 };
console.log(a); // {x: 2}

ES2015 之后,各处都允许重复的属性名称,包括 严格模式。你还可以在 classes 中拥有重复的属性名称。唯一的例外是 私有属性,它在类主体中必须是唯一的。

¥After ES2015, duplicate property names are allowed everywhere, including strict mode. You can also have duplicate property names in classes. The only exception is private properties, which must be unique in the class body.

方法定义

¥Method definitions

对象的属性还可以引用 functiongettersetter 方法。

¥A property of an object can also refer to a function or a getter or setter method.

js
const o = {
  property: function (parameters) {},
  get property() {},
  set property(value) {},
};

可以使用简写符号,因此不再需要关键字 function

¥A shorthand notation is available, so that the keyword function is no longer necessary.

js
// Shorthand method names
const o = {
  property(parameters) {},
};

还有一种方法可以简洁地定义生成器方法。

¥There is also a way to concisely define generator methods.

js
const o = {
  *generator() {
    // …
  },
};

这相当于类似 ES5 的表示法(但请注意 ECMAScript 5 没有生成器):

¥Which is equivalent to this ES5-like notation (but note that ECMAScript 5 has no generators):

js
const o = {
  generator: function* () {
    // …
  },
};

有关方法的更多信息和示例,请参阅 方法定义

¥For more information and examples about methods, see method definitions.

计算属性名称

¥Computed property names

对象初始值设定项语法还支持计算属性名称。这允许你将表达式放在方括号 [] 中,该表达式将被计算并用作属性名称。这让人想起 属性访问器 语法的括号表示法,你可能已经使用它来读取和设置属性。

¥The object initializer syntax also supports computed property names. That allows you to put an expression in square brackets [], that will be computed and used as the property name. This is reminiscent of the bracket notation of the property accessor syntax, which you may have used to read and set properties already.

现在你也可以在对象文字中使用类似的语法:

¥Now you can use a similar syntax in object literals, too:

js
// 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}

传播特性

¥Spread properties

对象字面量支持 扩展语法。它将自己的可枚举属性从提供的对象复制到新对象上。

¥Object literals support the spread syntax. It copies own enumerable properties from a provided object onto a new object.

现在可以使用比 Object.assign() 更短的语法进行浅克隆(不包括 prototype)或合并对象。

¥Shallow-cloning (excluding prototype) or merging objects is now possible using a shorter syntax than Object.assign().

js
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() 触发 setters,而扩展语法则不会!

¥Warning: Note that Object.assign() triggers setters, whereas the spread syntax doesn't!

原型制定者

¥Prototype setter

__proto__: value"__proto__": value 形式的属性定义不会创建名称为 __proto__ 的属性。相反,如果提供的值是对象或 null,它会将创建的对象的 [[Prototype]] 指向该值。(如果该值不是对象或 null,则对象不会更改。)

¥A property definition of the form __proto__: value or "__proto__": value does not create a property with the name __proto__. Instead, if the provided value is an object or null, it points the [[Prototype]] of the created object to that value. (If the value is not an object or null, the object is not changed.)

请注意,与非标准和非性能的 Object.prototype.__proto__ 访问器相比,__proto__ 键是标准化语法。它在对象创建期间设置 [[Prototype]],类似于 Object.create — 而不是改变原型链。

¥Note that the __proto__ key is standardized syntax, in contrast to the non-standard and non-performant Object.prototype.__proto__ accessors. It sets the [[Prototype]] during object creation, similar to Object.create — instead of mutating the prototype chain.

js
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

对象字面量中只允许使用单个原型设置器。多个原型设置器是一个语法错误。

¥Only a single prototype setter is permitted in an object literal. Multiple prototype setters are a syntax error.

不使用 "colon" 表示法的属性定义不是原型设置器。它们是属性定义,其行为与使用任何其他名称的类似定义相同。

¥Property definitions that do not use "colon" notation are not prototype setters. They are property definitions that behave identically to similar definitions using any other name.

js
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)

规范

Specification
ECMAScript Language Specification
# sec-object-initializer

¥Specifications

浏览器兼容性

BCD tables only load in the browser

¥Browser compatibility

也可以看看