物件初始化器

Baseline 已廣泛支援

此特性已相當成熟,可在許多裝置和瀏覽器版本上使用。自 ⁨2015 年 7 月⁩以來,各瀏覽器均已提供此特性。

物件初始化器是一個由零個或多個屬性名及其關聯值的對組成的、用逗號分隔的列表,用花括號 ({}) 括起來。物件也可以使用 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"

語法

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 初始化的表示式。物件由用於描述物件的“屬性”組成。物件屬性的值可以包含原始資料型別或其他物件。

物件字面量語法 vs. JSON

物件字面量語法與 JavaScript Object Notation (JSON) 不同。儘管它們看起來相似,但它們之間存在差異。

  • JSON“只”允許使用 "property": value 語法定義屬性。屬性名必須用雙引號括起來,並且定義不能是簡寫形式。也不允許使用計算屬性名。
  • JSON 物件屬性值只能是字串、數字、truefalsenull、陣列或另一個 JSON 物件。這意味著 JSON 不能表示方法或非普通物件,例如 MapRegExp
  • 在 JSON 中,"__proto__" 是一個普通的屬性鍵。在物件字面量中,它設定了物件的原型

JSON 是物件字面量語法的“嚴格子集”,這意味著每個有效的 JSON 文字都可以被解析為物件字面量,並且很可能不會導致語法錯誤。唯一的例外是物件字面量語法禁止重複的 __proto__ 鍵,這不適用於 JSON.parse()。後者將 __proto__ 視為普通屬性,並取最後一次出現的作為屬性值。它們所代表的物件值(即它們的語義)唯一不同的時候是源包含 __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() {
    return 1;
  },
  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() 會觸發設定器,而擴充套件語法不會!

原型設定器

形式為 __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® 2026 語言規範
# sec-object-initializer

瀏覽器相容性

另見