2019-6-19
第四章 扩展的对象功能
(一)对象字面量
属性初始化器的速记法
当对象的属性名称与本地变量名称相同时,可以只书写名称,省略冒号和值
let name = "xiaoming",
age = 30,
obj = {
name, //非省略写法 name: name
age //非省略写法 age: age
}
方法简写
方法简写能使用super,非简写的方法则不能
var person = {
name: 'xiaoming',
sayName() { //非省略写法 say: function() {}
console.log(this.name);
}
}
可计算属性名
[]表示法允许将任意字符串用作属性名,可用于对象实例和对象字面量中
var person = {},
lastName = "last name";
// 用于实例
person["first name"] = 'Nicholes';
person[lastName] = 'Zakas';
//用于对象字面量
person = {
"first Name": 'Nicholes',
[lastName]: 'Zakas'
};
var suffix = " name";
var person = {
["first" + suffix]: "Nicholas",
["last" + suffix]: "Zakas"
};
(二)新的方法
Object.is()
弥补 ”===“ 认为+0与-0相等的缺陷
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
Object.assign(receive,source1, source2...)
参数:接受一个接收者对象,和任意个源对象,将源对象上的属性浅复制到接收者对象上,然后返回接收者对象。
//Object.assign()的实现源码
function mixin(receiver, supplier) {
Object.keys(supplier).forEach(function(key) {
receiver[key] = supplier[key];
});
return receiver;
}
**注意:**不能将源对象的访问器属性复制给接收者对象,因为使用了赋值运算符,源对象的访问器属性会转变为接收对象的数据属性
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
(三)重复的对象字面量属性
无论是否在严格模式,ES6都不再检查重复的对象字面量属性,当存在重复属性时,后面的会覆盖前面的。
"use strict";
var person = {
name: "Nicholas",
name: "Greg" // no error in ES6 strict mode
};
console.log(person.name); // "Greg"
(四) 自有属性的枚举顺序
- 数字 =》 升序
- 字符串、符号 =》 按添加顺序
在对象字面量中定义的属性会首先出现,然后才是动态添加到对象中的键
var obj = {
a: 1,
0: 1,
c: 1,
2: 1,
b: 1,
1: 1,
e: 1
};
obj.d = 1;
console.log(Object.getOwnPropertyNames(obj).join("")); // "012acbed"
(五) 原型
-
修改原型
Object.create(); 创建对象时指定原型
Object.getPrototypeOf(); 获取对象原型
Object.setPrototypeOf(); 修改对象原型
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引用
super 是指向当前对象的原型的一个指针,可以使用super来调用对象原型上的任何方法,只要这个引用是位于简写的方法之内。
let person = {
getGreeting() {
return "Hello";
}
};
let friend = {
getGreeting() {
// 在这里super.getGreeting 等价于 Object.getPrototypeOf(this).getGreeting.call(this)
// return Object.getPrototypeOf(this).getGreeting.call(this) + ", hi!";
return super.getGreeting() + ", hi!";
}
};
// set prototype to person
Object.setPrototypeOf(friend, person);
console.log(friend.getGreeting()); // "Hello, hi!"
console.log(Object.getPrototypeOf(friend) === person); // true
// 不在简写的方法内引用super,会导致语法错误
let friend = {
getGreeting: function() {
// 语法错误
return super.getGreeting() + ", hi!";
}
};
super引用不是动态的,所以它总能指向正确的对象,可以轻松实现多级继承
let person = {
getGreeting() {
return "Hello";
}
};
// prototype is person
let friend = {
getGreeting() {
return Object.getPrototypeOf(this).getGreeting.call(this) + ", hi!";
}
};
Object.setPrototypeOf(friend, person);
// prototype is friend
let relative = Object.create(friend);
console.log(person.getGreeting()); // "Hello"
console.log(friend.getGreeting()); // "Hello, hi!"
//relative的原型是friend, friend.getGreeting().call()调用会导致进程开始反复进行递归调用,直至发生堆栈错误
console.log(relative.getGreeting()); // error!
// prototype is person
let friend = {
getGreeting() {
// super是非动态的,这里的super.getGreeting始终指向person.getGreeting()
return super.getGreeting() + ", hi!";
}
};
Object.setPrototypeOf(friend, person);
// prototype is 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]]**内部属性的函数,[[HomeObject]]指向该方法所属的对象。
let person = {
// method
getGreeting() { // [[HomeObject]]指向person
return "Hello";
}
};
// not a method
function shareGreeting() { // 无[[HomeObject]]属性
return "Hi!";
}
任何对super的引用都会使用[[HomeObject]]属性来判断要做什么:
- 在[[HomeObject]]上调用Object.getPrototypeOf()来获取对原型的引用;
- 在该原型上查找同名函数;
- 创建this绑定并调用该方法。