对象字面量的语法扩展
属性初始值的简写
在ES6中,当一个对象的属性与本地变量同名时,不必再写冒号和值,简单的只写属性名即可。当对象字面量里只有一个属性的名称时,JavaScript引擎会在可访问作用域中查找其同名变量;如果找到,则该变量的值被赋给对象字面量里的同名属性。
function getPerson(name, age) {
return {
name: name,
age: age
}
}
// 简写↓
function getPerson(name, age) {
return {
name,
age
}
}
对象方法的简写语法
消除了冒号和function关键字。
const person = {
name: 'apple',
sayName: function() {
console.log(this.name);
}
}
// 简写↓
const person = {
name: 'apple',
sayName() {
console.log(this.name);
}
}
两者唯一的区别是:简写方法可以使用super关键字
可计算属性名
在ES5,如果想要通过计算得到属性名,就需要用方括号代替点记法。此外,在对象字面量中,可以直接使用子符串字面量作为属性的名称。
在ES6,可在对象字面量中使用可计算属性名称,其语法与引用对象实例的可计算属性名称相同,也是使用方括号。同样可以使用表达式作为属性的可计算名称。
// ES5
const person {
'first name': 'first name'
},
lastName = 'last Name'
person['second name'] = 'second name';
person[lastName] = 'last name';
console.log(person);
/*{
'first name': 'first name',
'second name': 'second name',
'last name' = 'last name'
}*/
//ES6 ↓
const lastName = 'last Name',
name = 'name';
const person {
'first name': 'first name',
['midle' + name]: 'middle name'
[lastName]: 'last name',
};
console.log(person);
/*{
'first name': 'first name',
'second name': 'second name',
'last name' = 'last name'
}*/
新增方法
Object.is()方法
ES6引入Object.is()方法来补全全等运算符的不准确运算。这个方法接受两个参数,如果这两个参数类型相同且具有相同的值,则返回true。
是否选择用Object.is()方法而不是==或===取决于那些特殊情况如何影响代码。
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()方法
ES6添加了Object.assign()方法来实现一个对象接受另一个对象的属性和方法,这个方法接受一个接收对象和任意数量的源对象,并按制定顺序将属性赋值到接收对象中,如果多个源对象具有同名属性,则排位靠后的源对象会覆盖排位靠前的,最终返回接收对象。
function EventTarget(){/*...*/}
EventTarget.prototype = {
constructor: EventTarget,
emit: function(){/*...*/},
on: function(){/*...*/}
}
const myObj = {};
Object.assign(myObj, EventTarget.prototype);
console.log(myObj.emit());
const receiver = {};
Object.assign(receiver, {
type: 'js',
name: 'file.js'
}, {
type: 'css'
});
console.log(receiver.type); // css
重复的字面量属性
ES6中重复属性检车被移除了,代码不在检查重复属性,对每一组重复属性,都会选取最后一个取值。
const person = {
name: 'apple',
name: 'banana'
}
console.log(person.name); // banana
自由属性枚举顺序
ES6严格规定了对象的自有属性被枚举时的返回顺序,这会影响到Object.getOwnPropertyNames()方法以及Reflect.ownKeys返回属性的方式,Object.assign方法的处理顺序也将随之改变。
自有属性枚举顺序的基本规则是:
- 所有数字键按升序排序
- 所有字符串键按它们被加入对象的顺序排序
- 所有Symbol键按照它们被加入对象的顺序排序
const obj = {
a: 1,
0: 1,
c: 1,
2: 1,
b: 1,
1: 1
}
obj.d = 1;
console.log(Object.getOwnPropertyNames(obj).join('')); // '012acbd'
增强对象的原型
改变对象的原型
正常情况下,无论是通过构造函数还是Object.create()方法创建对象,其原型是在对象被创建是制定的。对象原型在实例化后保持不变。ES6添加了Object.setProrotyprOf()方法来改变这一现状,通过这个方法可以改变任意制定对象的原型,它接受两个参数:被改变原型的对象以及替代第一个参数原型的对象。
let person = {
getGreeting() {
return 'Hello';
}
}
let dog = {
getGreeting() {
return 'Woof';
}
}
// 以person对象为原型
let friend = Object.create(person);
console.log(friend.getGreeting()); // 'Hello'
console.log(Object.getPrototyeOf(friend) === person); // true
//将原型设置为dog
Object.setPrototyeOf(friend, dog);
console.log(friend.getGreeting()); // 'Woof'
console.log(Object.getPrototyeOf(friend) === dog); // true
对象原型的真实值被储存在内部专用属性[[Protrtype]]中,调用Object.getPrototyeOf()方法返回存储其中的值,调用Object.setPrototyeOf()方法改变其中的值。
简化原型访问的Super引用
ES6引入了Super引用的特性,使用它可以更便捷地访问对象原型。Super引用相当于指向对象原型的指针,也就是Object.getPrototypeOf(this)的值。可以通过Super引用调用对象原型上多有其他方法,必须要在使用简写方法的对象中使用Super引用。此时的this绑定会被自动设置为当前作用域的this值
let person = {
getGreeting() {
// Object.getPrototypeOf(this).getGreeting().call(this)相同
return super.getGreeting() + ', Hi!';
},
getGreeting2: function() {
// 语法错误
return super.getGreeting() + ', Hi!';
}
}
Super引用在多重继承的情况下非常有用。Super的引用不是动态变化的,它总是指向正确的对象。
let person = {
getGreeting() {
return 'Hello';
}
}
// 以person为原型
let friend = {
getGreeting() {
return super.getGreeting() + ', Hi!';
},
}
Object.setPrototypeOf(friend, person);
// 原型是friend
let relative = Object.create(friend);
console.log(person.getGreeting()); // Hello
console.log(friend.getGreeting()); // Hello, Hi!
console.log(relative.getGreeting()); // Hello, Hi!
正确的方法定义
ES6中正式将方法定义为一个函数,它会有一个内部的[[HomeObject]]属性来容纳这个方法从属的对象。
let person = {
// 是方法
getGreeting() {
return 'Hello';
}
}
// 不是方法
function getGreeting() {
return 'Hi';
}
Super的所有引用都是通过[[HomeObject]]属性来确定后续的运行过程。第一步是在[[HomeObject]]属性上调用Object.getPrototypeOf()方法来检索原型的引用;然后搜寻原型找到同名函数;最后,设置this(当前作用域)绑定并且调用相应的方法。