# ES6之对象的扩展

# 一. 属性的简洁表示

在ES6中,当属性名与属性值相同时,可省略属性值。

// 属性简写
let a = 'bar';
let b = {a};
b // {a: "bar"}

// 等同于
let b = {a: a};


// 方法简写
let obj = {
  method() {
    return "Hello World!";
  }
};

// 等同于
let obj  = {
  method: function() {
    return "Hello World!";
  }
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

以下是实际场景

let age = 29;

let user = {

  name: '浪子快跑',

  //等同于age: age
  age,

  // 等同于say: function ()...
  say() { console.log('my name is', this.name); }

};
1
2
3
4
5
6
7
8
9
10
11
12
13

简写的对象方法不能用作构造函数,会报错

const obj = {
  f() {
    this.foo = 'bar';
  }
};

new obj.f() // 报错
1
2
3
4
5
6
7

# 二. 属性名表达式

ES6 允许字面量定义对象时,用(表达式)作为对象的属性名,即把表达式放在方括号内

let key = 'foo';

let obj = {
  [key]: true,
  ['a' + 'bc']: 123
};

console.log(obj1.foo, obj1.abc) // true 123
1
2
3
4
5
6
7
8

注意

  • 属性名表达式与简洁表示法,不能同时使用,会报错
// 报错
const foo = 'bar';
const bar = 'abc';
const baz = { [foo] };

// 正确
const foo = 'bar';
const baz = { [foo]: 'abc'};
1
2
3
4
5
6
7
8
  • 属性名表达式如果是一个对象,默认情况下会自动将对象转为字符串[object Object]
const key1 = {a: 1};
const key2 = {b: 2};

const obj = {
  [key1]: 'valueA',
  [key2]: 'valueB'
};

obj  // Object {[object Object]: "valueB"}

// [key1]和[key2]得到的都是[object Object],
// 所以[key2]会把[key1]覆盖掉,而obj最后只有一个[object Object]属性。
1
2
3
4
5
6
7
8
9
10
11
12

# 三. 可枚举性

对象的每个属性都有一个描述对象,用来控制该属性的行为。
Object.getOwnPropertyDescriptor方法可以获取该属性的描述对象。

let obj = { foo: 123 };
Object.getOwnPropertyDescriptor(obj, 'foo')
//  {
//    value: 123,
//    writable: true,
//    enumerable: true,
//    configurable: true
//  }
1
2
3
4
5
6
7
8

目前,有四个操作会忽略enumerable为false的属性。

for...in循环:只遍历对象自身的和继承的可枚举的属性。
Object.keys():返回对象自身的所有可枚举的属性的键名。
JSON.stringify():只串行化对象自身的可枚举的属性。
Object.assign(): 忽略enumerable为false的属性,只拷贝对象自身的可枚举的属性。

# 四. super 关键字

ES6 新增了关键字super,指向当前对象的原型对象。

const proto = {
  foo: 'hello'
};

const obj = {
  foo: 'world',
  find() {
    return super.foo;
  }
};

Object.setPrototypeOf(obj, proto);
obj.find() // "hello"
1
2
3
4
5
6
7
8
9
10
11
12
13

注意:super关键字表示原型对象时,只能用在对象的方法之中,用在其他地方都会报错。

// 报错
const obj = {
  foo: super.foo
}

// 报错
const obj = {
  foo: () => super.foo
}

// 报错
const obj = {
  foo: function () {
    return super.foo
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

下面代码中,super.foo指向原型对象proto的foo方法,但是绑定的this却还是当前对象obj,因此输出的是world。

const proto = {
  x: 'hello',
  foo() {
    console.log(this.x);
  },
};

const obj = {
  x: 'world',
  foo() {
    super.foo();
  }
}

Object.setPrototypeOf(obj, proto);

obj.foo() // "world"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 五. 对象的扩展运算符

####1. 扩展运算符 对象的扩展运算符(...)用于取出参数对象的所有可遍历属性,然后拷贝到当前对象之中。

let a = {x:1, y:2}
let b = {...a}
// b = {x:1, y:2}

// 合并两个对象,当有相同属性时,后面的覆盖前面的
let a = {x:1, y:2}
let b = {x1:3, y:4}
let c = {...a, ...b}
// c = {x: 1, y: 4, x1: 3}

// 对象的扩展运算符后面可以跟表达式
const obj = {
  ...(x > 1 ? {a: 1} : {}),
  b: 2,
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

注意:对象的扩展运算符,只会返回参数对象自身的、可枚举的属性

#####2. 解构赋值

let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };
x // 1
y // 2
z // { a: 3, b: 4 }

// 解构赋值时右边需是一个对象,否则报错
let { ...z } = null; // 运行时错误
let { ...z } = undefined; // 运行时错误

// 解构赋值必须是最后一个参数
let { ...x, y, z } = someObject; // 句法错误
let { x, ...y, ...z } = someObject; // 句法错误

// 扩展运算符的解构赋值,不能复制继承自原型对象的属性
let o1 = { a: 1 };
let o2 = { b: 2 };
o2.__proto__ = o1;
let { ...o3 } = o2;
o3 // { b: 2 }
o3.a // undefined
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

注:本文只记录了日常开发中常用的更新

参考资料
阮一峰 ES6 入门教程 (opens new window)