Object initializer

对象可以通过 new Object(), Object.create() 方法, 或者使用字面 标记 (初始化 标记)初始化。 对象初始化,由花括号{}包含的一个由0个或者多个对象属性名和关联值组成的列表构成。

语法

let obj = {};
let obj = { a: "foo", b: 42, c: {} };
let a = "foo", b = 42, c = {};
let obj = { a: a, b: b, c: c };
let obj = {
  property: function ([parameters]) {},
  get property() {},
  set property(value) {},
};

ECMAScript 6新标记

请参考兼容性表格获取这些标记的支持信息。在不被支持的环境中,这些标记将造成语法错误。

// Shorthand property names (ES6)
let a = "foo", b = 42, c = {};
let obj = { a, b, c };
// Shorthand method names (ES6)
let obj = {
    property([parameters]) {},
    get property() {},
    set property(value) {},
    * generator() {}
};
// Computed property names (ES6)
let prop = "foo";
let obj = {
    [prop]: "hey",
    ["b" + "ar"]: "there",
};

描述

对象初始化是一个描述对象初始化过程的表达式。对象初始化是由一组描述对象的属性组成。属性的值可以是固有类型,也可以是其他对象。

创建对象

没有属性的空对象可以用以下方式创建:

let obj = {};

不过,字面 初始化 标记的优势在于,可以用内含属性的花括号快速创建对象。简单地编写一个逗号分隔的键:值对的类别。如下代码创建了一个含三个属性的对象,键分别为 "foo", "age" 和 "baz"。这些键对应的值,分别是字符串“bar”,数字42和另一个对象。

let obj = {
  foo: "bar",
  age: 42,
  baz: { myProp: 12 },
}

属性访问

创建对象后,可以读取或者修改它。对象属性可以用下标小圆点标记或者方括号标记访问。参考属性访问 获取更多信息。

object.foo; // "bar"
object["age"]; // 42
object.foo = "baz";

属性定义

上面学习了如何用初始化标记对象属性。经常能遇到希望将代码中的变量放到对象中的情况。可能遇到如下代码:

var a = "foo",
    b = 42,
    c = {};
var o = {
  a: a,
  b: b,
  c: c
};

在 ECMAScript 2015中,有更简短的标记可以实现同样的效果:

let a = "foo",
    b = 42,
    c = {};
// Shorthand property names (ES6)
let obj = { a, b, c };

Demo:

ES6-Object-initializer

重复属性名

属性使用了同样的名称时,后面的属性会覆盖前面的属性。

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

在 ECMAScript 5 strict 模式的代码中, 重复的属性名会被当做SyntaxError。引入计算的属性名以后,属性名会在运行时出现重复。ECMAScript 2015 移除了这个限制。

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

方法定义

对象属性也可以是一个函数gettersetter方法。

var o = {
  property: function ([parameters]) {},
  get property() {},
  set property(value) {},
};

ECMAScript 2015引入了一中简短写法, "function" 关键字也可以丢掉。

// Shorthand method names (ES6)
var o = {
  property([parameters]) {},
  get property() {},
  set property(value) {},
  * generator() {}
};

ECMAScript 2015 提供了一种简明地定义以生成器函数作为值的属性的方法。

var o = {
  * generator() {
    ...........
  }
};

ECMAScript 5 中可以这样书写 (需要注意的时 ES5 没有生成器):

var o = {
  generatorMethod: function *() {
    ...........
  }
};

获取更多信息和范例,请参考 method definitions

计算的属性名

从ECMAScript 2015开始,对象初始化语法开始支持计算的属性名。其允许在[]中放入表达式,计算结果可以当做属性名。这种用法和用方括号访问属性非常类似,也许你已经用来读取和设置属性了。现在同样的语法也可以用于对象字面值了:

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

变更原型

定义属性为__proto__: 值"__proto__": 值 时,不会创建名为__proto__属性。如果给出的值是对象或者null,那么对象的[[Prototype]]会被设置为给出的值。(如果给出的值不是对象也不是null,那么对象的原型不会改变。)

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__"));

在对象字面值中,仅有一次变更原型的机会;多次变更原型,会被视为语法错误。

不使用冒号标记的属性定义,不会变更对象的原型;而是和其他具有不同名字的属性一样是普通属性定义。

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

对象字面值记法和JSON

对象字面值记法和和 JavaScript Object Notation (JSON)是不同的。虽然他们看起来相似,不同点有:

  • JSON 只允许"property": value syntax形式的属性定义。属性名必须用双引号括起来。且属性定义不允许使用简便写法。
  • JSON中,属性的值仅允许字符串,数字,数组,true,false,或者其他JSON对象。 
  • JSON中,不允许将值设置为函数。
  •  Date 等对象,经JSON.parse()处理后,会变成字符串。
  • JSON.parse() 不会处理计算的属性名,会当做错误抛出。

规范

规范 状态 备注
ECMAScript 1st Edition. Standard 初始定义
ECMAScript 5.1 (ECMA-262)
Object Initializer
Standard 增加Gettersetter 
ECMAScript 2015 (6th Edition, ECMA-262)
Object Initializer
Standard 增加method/property 简写方法和计算的属性名

浏览器兼容性

特性 Chrome Firefox (Gecko) Internet Explorer Opera Safari
Basic support

1.0

1.0 (1.7 or earlier) 1 1 1
Computed property names 未实现 34 (34) 未实现 未实现 7.1.3
Shorthand property names 未实现 33 (33) 未实现 未实现 未实现
Shorthand method names

42.0

34 (34) 未实现 未实现 未实现
特性 Android Android Webview Firefox Mobile (Gecko) IE Mobile Opera Mobile Safari Mobile Chrome for Android
Basic support

(Yes)

(Yes) 1.0 (1.0) 1 1 1 1.0
Computed property names 未实现 (Yes) 34.0 (34) 未实现 未实现 未实现 未实现
Shorthand property names 未实现 (Yes) 33.0 (33) 未实现 未实现 未实现 未实现
Shorthand method names

未实现

42.0 34.0 (34) 未实现 未实现 未实现 42.0

参见

文档标签和贡献者