ES6之对象

对象字面量语法扩展

属性初始值的简写

1
2
3
4
5
6
function createPerson(name, age) {
return {
name: name,
age: age
};
}

属性与为属性赋值的变量是重复的,可以简写为:

1
2
3
4
5
6
function createPerson(name, age) {
return {
name,
age
};
}

这样可以避免命名错误以及不小心的拼写错误。

对象方法的简写

1
2
3
4
5
6
var person = {
name: "Nicholas",
sayName: function() {
console.log(this.name);
}
};

可以简写为:

1
2
3
4
5
6
var person = {
name: "Nicholas",
sayName() {
console.log(this.name);
}
};

简写方法sayName里面可以使用super关键字;

可计算属性名

ES5及早期版本的对象实例中,如果想要通过计算得到属性名,就需要用方括号代替点记法。并且有空格的字符串不能直接作为属性名,也需要方括号代替;

1
2
3
4
5
6
var person = {},
lastName = "last name";
person["first name"] = "Nicholas";
person[lastName] = "Zakas";
console.log(person["first name"]);
console.log(person[lastName]);

ES6中,可在对象字面量中使用可计算属性名称,其语法与引用对象实例的可计算属性名称相同,也是使用方括号。

1
2
3
4
5
6
7
let lastName = "last name";
let person = {
"first name": "Nicholas",
[lastName]: "Zakas"
};
console.log(person["first name"]);
console.log(person[lastName]);

新增方法

Object.is

在JS中比较两个值,使用===跟==比较多,但是===在有些情况也不完全准确;+0与-0在JS引擎中是两个完全不同的实体,NaN === NaN 返回值为false,需要用isNaN()才能检测出NaN;

1
2
3
4
5
6
7
8
9
10
11
12
console.log(+0 == -0); // true
console.log(+0 === -0); // true
console.log(Object.is(+0, -0)); // false
console.log(NaN == NaN); // false
console.log(NaN === NaN); // false
console.log(Object.is(NaN, NaN)); // true
console.log(5 == 5); // true
console.log(5 == "5"); // true
console.log(5 === 5); // true
console.log(5 === "5"); // false
console.log(Object.is(5, 5)); // true
console.log(Object.is(5, "5")); // false

Object.assign

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var receiver = {};
var test = {name: 'zakas'};
Object.assign(receiver,
{
type: "js",
name: "file.js"
},
{
type: "css",
data: test,
}
);
console.log(receiver.type); // css
console.log(receiver.name); // file.js
console.log(receiver.data); // {name: 'zakas'}
test.name = 'hi';
console.log(receiver.data); // {name: 'hi'}

Object.assign参数后面的对象会覆盖前面的对象,并且为浅复制;

Object.assign会把访问器属性复制为数据属性;

1
2
3
4
5
6
7
8
9
10
var receiver = {},
supplier = {
get name() {
return "file.js"
}
};
Object.assign(receiver, supplier);
var descriptor = Object.getOwnPropertyDescriptor(receiver, "name");
console.log(descriptor.value); // "file.js"
console.log(descriptor.get); // undefined

重复的对象字面量属性

ES5严格模式重复字面量属性会报错;ES6无论严格或者非严格模式下,重复属性都会选取最后一个取值;

1
2
3
4
5
6
"use strict";
var person = {
name: "Nicholas",
name: "Greg" // no error in ES6 strict mode
};
console.log(person.name); // Greg

自有属性枚举顺序

  1. 所有数字键按升序排列
  2. 所有字符串键按照它们被加入对象的顺序排序
  3. 所有symbol按照它们被加入的顺序排序
1
2
3
4
5
6
7
8
9
10
11
var obj = {
a: 1,
0: 1,
c: 1,
2: 1,
b: 1,
1: 1
};
obj.d = 1;
console.log(Object.getOwnPropertyNames(obj).join(""));
// 012acbd

增强对象原型

改变对象的原型setPrototypeOf

对象原型的真实值被储存在内部的专用属性[[Prototype]]中,调用Object.getPrototypeOf返回储存在其中的值,调用Object.setPrototypeOf方法改变其中的值;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
let person = {
getGreeting() {
return "Hello";
}
};
let dog = {
getGreeting() {
return "Woof";
}
};
// prototype is person
let friend = Object.create(person);
console.log(friend.getGreeting()); // Hello
console.log(Object.getPrototypeOf(friend) === person); // true
// set prototype to dog
Object.setPrototypeOf(friend, dog);
console.log(friend.getGreeting()); // "Woof"
console.log(Object.getPrototypeOf(friend) === dog); // true

简化原型访问的Super引用

ES6引入了super关键字,super引用相当于指向对象原型的指针,实际上也就是Object.getPrototypeOf()的效果;

1
2
3
4
5
6
let friend = {
getGreeting() {
// in the previous example, this is the same as:
// Object.getPrototypeOf(this).getGreeting.call(this)
return super.getGreeting() + ", hi!";
} };

super关键字必须要在使用简写方法的对象中使用super引用,如果在其他方法声明中使用会导致语法错误;

1
2
3
4
5
let friend = {
getGreeting: function() {// syntax error
return super.getGreeting() + ", hi!"; // 'super' keyword unexpected here
}
};

正式的方法定义

ES6正式将方法定义为一个函数,它会由一个内部的[[HomeObject]]属性来容纳这个方法从属的对象;

1
2
3
4
5
6
7
8
9
10
let person = {
// method
getGreeting() {
return "Hello";
}
};
// not a method
function shareGreeting() {
return "Hi!";
}

上段代码的getGreeting方法的[[HomeObject]]属性值为person,而创建shareGreeting函数时,由于未将其赋值给一个对象,因为该方法没有明确定义[[HomeObject]]属性。

super的所有引用都通过[[HomeObject]]属性调用Object.getPrototypeOf方法来检索原型的引用;然后搜寻原型找到同名函数;最后,设置this绑定并且调用相应的方法;

1
2
3
4
5
6
7
8
9
10
11
12
let person = {
getGreeting() {
return "Hello";
}
};
// prototype is person
let friend = {
getGreeting() {
return super.getGreeting() + ", hi!";
} };
Object.setPrototypeOf(friend, person);
console.log(friend.getGreeting());

friend.getGreeting()方法的[[HomeObject]]的属性值时friend,friend的原型是person,所以super.getGreeting()等价于person.getGreeting.call(this);