对象初始化器

**对象初始化器** 是一个用花括号 ({}) 括起来的零个或多个属性名称和相关值对的逗号分隔列表,用于描述对象的初始化。也可以使用 Object.create()通过使用 new 运算符调用构造函数 来初始化对象。

试试看

语法

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

描述

对象初始化器是一个表达式,描述了 Object 的初始化。对象由属性组成,用于描述对象。对象属性的值可以包含 基本 数据类型或其他对象。

对象字面量语法与 JSON

对象字面量语法与 JavaScript Object Notation (JSON) 不同。虽然它们看起来很相似,但它们之间存在差异

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

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

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)

示例

创建对象

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

js
const object = {};

但是,字面量初始化器表示法的优点是,您可以快速创建在花括号内带有属性的对象。您用逗号分隔的 key: value 对列表来表示。

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

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

访问属性

创建对象后,您可能想要读取或更改它们。可以使用点表示法或方括号表示法来访问对象属性。(有关详细信息,请参阅 属性访问器。)

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

属性定义

我们已经了解了如何使用初始化器语法来表示属性。通常,您的代码中有一些变量,您想将它们放入对象中。你会看到这样的代码

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

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

可以使用更简短的表示法来实现相同的结果

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

重复的属性名

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

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

在 ES2015 之后,重复的属性名称在所有地方都允许,包括 严格模式。您也可以在 中具有重复的属性名称。唯一的例外是 私有属性,它们在类主体中必须是唯一的。

方法定义

对象的属性也可以引用 函数gettersetter 方法。

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

可以使用简写表示法,这样就不再需要 function 关键字。

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

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

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

它等效于此 ES5 式表示法(但请注意 ECMAScript 5 没有生成器)

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

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

计算属性名

对象初始化器语法也支持计算属性名。这允许您在方括号 [] 中放入一个表达式,该表达式将被计算并用作属性名。这类似于您可能已经使用过的 属性访问器 语法的方括号表示法。

现在,您也可以在对象字面量中使用类似的语法

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}

展开属性

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

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

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() 会触发 setter,而展开语法不会!

原型设置器

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

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

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

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

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

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)

规范

规范
ECMAScript 语言规范
# sec-object-initializer

浏览器兼容性

BCD 表格仅在浏览器中加载

另请参阅