Skip to content

Commit 66932d0

Browse files
committed
add object/扩展运算符
1 parent 6d259c3 commit 66932d0

File tree

2 files changed

+120
-0
lines changed

2 files changed

+120
-0
lines changed

docs/iterator.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,10 @@ let obj = {
227227

228228
```javascript
229229
NodeList.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator];
230+
// 或者
231+
NodeList.prototype[Symbol.iterator] = [][Symbol.iterator];
232+
233+
[...document.querySelectorAll('div')] // 可以执行了
230234
```
231235

232236
如果Symbol.iterator方法返回的不是遍历器,解释引擎将会报错。

docs/object.md

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -481,3 +481,119 @@ Object.unobserve(o, observer);
481481
```
482482

483483
注意,Object.observe和Object.unobserve这两个方法不属于ES6,而是属于ES7的一部分。不过,Chrome浏览器从33版起就已经支持。
484+
485+
## 对象的扩展运算符
486+
487+
目前,ES7有一个[提案](https://github.com/sebmarkbage/ecmascript-rest-spread),将rest参数/扩展运算符(...)引入对象。Babel转码器已经支持这项功能。
488+
489+
**(1)Rest参数**
490+
491+
如果Rest参数用于从一个对象取值,就等于将所有可遍历、但尚未被读取的属性,分配到指定的对象上面。所有的键和它们的值,都会拷贝到新对象上面。
492+
493+
```javascript
494+
let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };
495+
x // 1
496+
y // 2
497+
z // { a: 3, b: 4 }
498+
```
499+
500+
上面代码中,变量z是Rest参数所在的对象。它获取等号右边的所有尚未读取的键(a和b),将它们和它们的值拷贝过来。
501+
502+
注意,Rest参数的拷贝是浅拷贝,即如果一个键的值是复合类型的值(数组、对象、函数)、那么Rest参数拷贝的是这个值的引用,而不是这个值的副本。
503+
504+
```javascript
505+
let obj = { a: { b: 1 } };
506+
let { ...x } = obj;
507+
obj.a.b = 2;
508+
x.a.b // 2
509+
```
510+
511+
上面代码中,x是Rest参数,拷贝了对象obj的a属性。a属性引用了一个对象,修改这个对象的值,会影响到Rest参数对它的引用。
512+
513+
另外,Rest参数不会拷贝继承自原型对象的属性。
514+
515+
```javascript
516+
let o1 = { a: 1 };
517+
let o2 = { b: 2 };
518+
o2.__proto__ = o1;
519+
let o3 = { ...o2 };
520+
o3 // { b: 2 }
521+
```
522+
523+
上面代码中,对象o3是o2的复制,但是只复制了o2自身的属性,没有复制它的原型对象o1的属性。
524+
525+
**(2)扩展运算符**
526+
527+
如果扩展运算符用于一个对象,就会将该对象的所有可遍历属性,拷贝到一个新对象,然后返回这个新对象。
528+
529+
```javascript
530+
let z = { a: 3, b: 4 };
531+
let n = { ...z };
532+
n // { a: 3, b: 4 }
533+
```
534+
535+
对象的扩展运算符,等同于使用`Object.assign`方法。
536+
537+
```javascript
538+
let aClone = { ...a };
539+
// 等同于
540+
let aClone = Object.assign({}, a);
541+
```
542+
543+
扩展运算符可以用于合并两个对象。
544+
545+
```javascript
546+
let ab = { ...a, ...b };
547+
```
548+
549+
扩展运算符还可以用自定义属性,会在新对象之中,覆盖掉原有参数。
550+
551+
```javascript
552+
let aWithOverrides = { ...a, x: 1, y: 2 };
553+
// 等同于
554+
let aWithOverrides = { ...a, ...{ x: 1, y: 2 } };
555+
// 等同于
556+
let x = 1, y = 2, aWithOverrides = { ...a, x, y };
557+
// 等同于
558+
let aWithOverrides = Object.assign({}, a, { x: 1, y: 2 });
559+
```
560+
561+
上面代码中,a对象的x属性和y属性,拷贝到新对象后会被覆盖掉。
562+
563+
如果把自定义属性放在扩展运算符前面,就变成了设置新对象的默认属性值。
564+
565+
```javascript
566+
let aWithDefaults = { x: 1, y: 2, ...a };
567+
// 等同于
568+
let aWithDefaults = Object.assign({}, { x: 1, y: 2 }, a);
569+
// 等同于
570+
let aWithDefaults = Object.assign({ x: 1, y: 2 }, a);
571+
```
572+
573+
扩展运算符的参数对象之中,如果有取值函数`get`,这个函数是会执行的。
574+
575+
```javascript
576+
// 并不会抛出错误,因为x属性只是被定义,但没执行
577+
let aWithXGetter = {
578+
...a,
579+
get x() {
580+
throws new Error('not thrown yet');
581+
}
582+
};
583+
584+
// 会抛出错误,因为x属性被执行了
585+
let runtimeError = {
586+
...a,
587+
...{
588+
get x() {
589+
throws new Error('thrown now');
590+
}
591+
}
592+
};
593+
```
594+
595+
如果扩展运算符的参数是null或undefined,这个两个值会被忽略,不会报错。
596+
597+
```javascript
598+
let emptyObject = { ...null, ...undefined }; // 不报错
599+
```

0 commit comments

Comments
 (0)