注:这是一篇学习笔记,记录自己在ES6学习过程中按照自己的思路觉得应该记录的一些要点,方便以后查看和复习。参考:
阮一峰ES6的书籍中函数的扩展
我的ES6入门学习规划
平常所说的对象属性,似乎都是指对象的那些跟值对应的属性,实际上属性除了有值属性,还有方法属性,这也是为啥在遍历对象的时候,能遍历出来的不单是那些值,还有对象的方法。 在掌握了属性描述符(PropertyDescriptor)之后,对属性的理解就会加深不少。
在对象扩展这个部分要特别注意以下几个点的适用情况:
- 是否包含继承属性
- 是否包含不可枚举属性
- setters, getters如何处理
- symbol值如何处理
属性的简洁表示法。
ES6在给对象定义值或方法的时,有更简洁的写法:1
2
3
4
5
6
7
8
9let foo = 'bar';
let baz = {foo};
baz.foo;//bar
const o = {
method() {
//...
}
}
setters, getters:1
2
3
4
5
6
7
8
9const card = {
_wheels: 4,
get wheels() {
return this._wheels;
}
set wheels(value) {
this._wheels = value;
}
}
generator函数,加星号:1
2
3
4
5const obj = {
* method() {
// ...
}
}
属性名表达式
在定义属性的时候,可以通过中括号使用表达式来表示属性名称:1
2
3
4
5
6
7
8
9
10
11let propKey = 'foo';
let obj = {
[propKey]: true,
['a' + 'bc']: 123,
[propKey + '_yes']() {
},
* [propKey + '_no']() {
yield 1;
}
}
- 属性名表达式不能与属性名简写同时使用
- 属性名表达式如果是一个对象,默认情况下会自动将对象转为字符串[object Object]
属性的可枚举性
对象的属性描述符上面有一个enumerable值,如果为true,则表示这个属性是可枚举的。有四个操作会忽略不可枚举的属性:
- for…in 只遍历对象自身和继承的可枚举属性
- Object.keys() 返回对象自身的所有可枚举属性的键名
- JSON.stringify() 只串行化对象自身的可枚举属性
- Object.assign() 只考虑对象自身的可枚举属性
这四个方法按照笔记一开始提到的注意点,重新整理如下:
api | 继承属性 | 不可枚举属性 | setter | getter | symbol |
---|---|---|---|---|---|
for…in | 包含 | 不包含 | 包含 | 包含 | 不包含 |
Object.keys() | 不包含 | 不包含 | 包含 | 包含 | 不包含 |
JSON.stringify() | 不包含 | 不包含 | 不包含 | 包含 | 不包含 |
Object.assign() | 不包含 | 不包含 | 包含 | 包含 | 包含 |
测试用例:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28let parent = {name: 'parent'};
let _birth;
let id = Symbol();
let child = {
set birth(birth) {
_birth = birth;
},
get birthday(){
return _birth;
},
[id]: 'lyzg',
__proto__: parent
};
child.birth = '0101';
console.log('for...in');
for(var i in child) {
console.log(i, child[i])
}
console.log('Object.keys()');
console.log(Object.keys(child));
console.log('JSON.stringify()');
console.log(JSON.stringify(child));
console.log('Object.assign()');
console.log(Object.assign({}, child));
注意:
- JSON.stringify()在串行化的时候,如果属性是一个getter,那么会把getter调用一次,并把返回值进行串行化
- Object.assign()在复制的时候,如果属性是一个getter,那么会把getter调用一次,并把返回值复制出来,而不是getter属性本身;Object.assign()在复制的时候,如果属性是一个单独的setter,没有getter与其对应,这个属性会以undefined为值进行复制,setter本身不会被复制
ES6规定所有Class的原型的方法都是不可枚举的。1
2Object.getOwnPropertyDescriptor(class {foo() {}}.prototype, 'foo').enumerable
// false
属性的遍历
目前有5种方法遍历对象的属性
- for…in: 遍历对象自身和继承的可枚举属性,不含Symbol属性
- Object.keys(obj): 可用来遍历对象自身的可枚举属性,不含Symbol属性
- Object.getOwnPropertyNames(obj): 可用来遍历对象自身的可枚举属性和不可枚举属性,不含Symbol属性
- Object.getOwnPropertySymbols(obj): 可用来遍历对象自身的所有Symbol属性
- Reflect.ownKeys(obj): 可用来遍历对象自身的所有属性,含Symbol属性, 含不可枚举属性
属性遍历的顺序规则:
- 首先遍历所有数字键属性,按数值升序;
- 其次遍历所有字符串键属性,按加入时间升序;
- 最后遍历所有Symbol键属性,按加入时间升序;
super关键字
指向对象的原型对象。 super关键字表示原型对象时,只能用在对象的方法之中,用在其他地方都会报错。只有对象方法的简写法可以让 JavaScript 引擎确认,定义的是对象的方法,用在其它地方会报错。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16// 报错
const obj = {
foo: super.foo
}
// 报错
const obj = {
foo: () => super.foo
}
// 报错
const obj = {
foo: function () {
return super.foo
}
}
JavaScript 引擎内部,super.foo等同于Object.getPrototypeOf(this).foo(值属性)或Object.getPrototypeOf(this).foo.call(this)(方法属性)。
对象扩展运算符
应用于两个方面。 一个是以前的笔记里记录过的对象解构,另外一个就是用于字面量对象创建的时候,从其它对象拷贝属性。举例:1
2
3let z = { a: 3, b: 4 };
let n = { ...z };
n // { a: 3, b: 4 }
它用于字面量对象定义时,作用是取出参数对象自身的所有可枚举属性,拷贝到待定义的字面量对象当中。如果参数不是对象,先将目标转为对象,再进行处理。null,undefined,boolean,string的作用结果如下:1
2
3
4
5
6
7
8
9
10// 等同于 {...Object(1)}
{...1} ;// {}
// 等同于 {...Object(true)}
{...true} ;// {}
// 等同于 {...Object(undefined)}
{...undefined}; // {}
// 等同于 {...Object(null)}
{...null} ;// {}
注意null,undefined值,对象扩展运算符使用的时候不会报错,但是数组的扩展运算符使用的时候会报错。
string,数组,NodeList对象,arguments对象,使用对象扩展运算符的时候,效果相同,都是把索引键与值拷贝出来。1
2
3let foo = { ...['a', 'b', 'c'] };
foo
// {0: "a", 1: "b", 2: "c"}
其它:与数组的扩展运算符一样,对象的扩展运算符后面可以跟表达式。
主要应用
- 对象的复制
- 对象的合并
对象的扩展运算符等同于Object.assign()方法。
复制:1
2
3let aClone = { ...a };
// 等同于
let aClone = Object.assign({}, a);
合并:1
2
3
4
5
6
7
8
9
10
11
12let ab = { ...a, ...b };
// 等同于
let ab = Object.assign({}, a, b);
//如果用户自定义的属性,放在扩展运算符后面,则扩展运算符内部的同名属性会被覆盖掉。
let aWithOverrides = { ...a, x: 1, y: 2 };
// x y 会覆盖a里面的x y
// 用来修改现有对象部分的属性就很方便
//如果把自定义属性放在扩展运算符前面,就变成了设置新对象的默认属性值
let aWithDefaults = { x: 1, y: 2, ...a };
// a里面的x y 会覆盖一开始的x y
对象扩展运算符用于字面量对象的行为整理如下:
api | 继承属性 | 不可枚举属性 | setter | getter | symbol |
---|---|---|---|---|---|
对象的扩展运算符 | 不包含 | 不包含 | 包含 | 包含 | 包含 |
注意点:如果属性是一个getter,那么会把getter调用一次,并把返回值复制出来,而不是getter属性本身;如果属性是一个单独的setter,没有getter与其对应,这个属性会以undefined为值进行复制,setter本身不会被复制。这一点与 Object.assign()是完全一样的。