From 66932d04189a4d435f16d63c61241e4e7da4c26e Mon Sep 17 00:00:00 2001 From: ruanyf Date: Tue, 25 Aug 2015 13:41:49 +0800 Subject: [PATCH] =?UTF-8?q?add=20object/=E6=89=A9=E5=B1=95=E8=BF=90?= =?UTF-8?q?=E7=AE=97=E7=AC=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/iterator.md | 4 ++ docs/object.md | 116 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 120 insertions(+) diff --git a/docs/iterator.md b/docs/iterator.md index ea4e0f5..7c4b349 100644 --- a/docs/iterator.md +++ b/docs/iterator.md @@ -227,6 +227,10 @@ let obj = { ```javascript NodeList.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator]; +// 或者 +NodeList.prototype[Symbol.iterator] = [][Symbol.iterator]; + +[...document.querySelectorAll('div')] // 可以执行了 ``` 如果Symbol.iterator方法返回的不是遍历器,解释引擎将会报错。 diff --git a/docs/object.md b/docs/object.md index 7062fa9..2e3f9cb 100644 --- a/docs/object.md +++ b/docs/object.md @@ -481,3 +481,119 @@ Object.unobserve(o, observer); ``` 注意,Object.observe和Object.unobserve这两个方法不属于ES6,而是属于ES7的一部分。不过,Chrome浏览器从33版起就已经支持。 + +## 对象的扩展运算符 + +目前,ES7有一个[提案](https://github.com/sebmarkbage/ecmascript-rest-spread),将rest参数/扩展运算符(...)引入对象。Babel转码器已经支持这项功能。 + +**(1)Rest参数** + +如果Rest参数用于从一个对象取值,就等于将所有可遍历、但尚未被读取的属性,分配到指定的对象上面。所有的键和它们的值,都会拷贝到新对象上面。 + +```javascript +let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 }; +x // 1 +y // 2 +z // { a: 3, b: 4 } +``` + +上面代码中,变量z是Rest参数所在的对象。它获取等号右边的所有尚未读取的键(a和b),将它们和它们的值拷贝过来。 + +注意,Rest参数的拷贝是浅拷贝,即如果一个键的值是复合类型的值(数组、对象、函数)、那么Rest参数拷贝的是这个值的引用,而不是这个值的副本。 + +```javascript +let obj = { a: { b: 1 } }; +let { ...x } = obj; +obj.a.b = 2; +x.a.b // 2 +``` + +上面代码中,x是Rest参数,拷贝了对象obj的a属性。a属性引用了一个对象,修改这个对象的值,会影响到Rest参数对它的引用。 + +另外,Rest参数不会拷贝继承自原型对象的属性。 + +```javascript +let o1 = { a: 1 }; +let o2 = { b: 2 }; +o2.__proto__ = o1; +let o3 = { ...o2 }; +o3 // { b: 2 } +``` + +上面代码中,对象o3是o2的复制,但是只复制了o2自身的属性,没有复制它的原型对象o1的属性。 + +**(2)扩展运算符** + +如果扩展运算符用于一个对象,就会将该对象的所有可遍历属性,拷贝到一个新对象,然后返回这个新对象。 + +```javascript +let z = { a: 3, b: 4 }; +let n = { ...z }; +n // { a: 3, b: 4 } +``` + +对象的扩展运算符,等同于使用`Object.assign`方法。 + +```javascript +let aClone = { ...a }; +// 等同于 +let aClone = Object.assign({}, a); +``` + +扩展运算符可以用于合并两个对象。 + +```javascript +let ab = { ...a, ...b }; +``` + +扩展运算符还可以用自定义属性,会在新对象之中,覆盖掉原有参数。 + +```javascript +let aWithOverrides = { ...a, x: 1, y: 2 }; +// 等同于 +let aWithOverrides = { ...a, ...{ x: 1, y: 2 } }; +// 等同于 +let x = 1, y = 2, aWithOverrides = { ...a, x, y }; +// 等同于 +let aWithOverrides = Object.assign({}, a, { x: 1, y: 2 }); +``` + +上面代码中,a对象的x属性和y属性,拷贝到新对象后会被覆盖掉。 + +如果把自定义属性放在扩展运算符前面,就变成了设置新对象的默认属性值。 + +```javascript +let aWithDefaults = { x: 1, y: 2, ...a }; +// 等同于 +let aWithDefaults = Object.assign({}, { x: 1, y: 2 }, a); +// 等同于 +let aWithDefaults = Object.assign({ x: 1, y: 2 }, a); +``` + +扩展运算符的参数对象之中,如果有取值函数`get`,这个函数是会执行的。 + +```javascript +// 并不会抛出错误,因为x属性只是被定义,但没执行 +let aWithXGetter = { + ...a, + get x() { + throws new Error('not thrown yet'); + } +}; + +// 会抛出错误,因为x属性被执行了 +let runtimeError = { + ...a, + ...{ + get x() { + throws new Error('thrown now'); + } + } +}; +``` + +如果扩展运算符的参数是null或undefined,这个两个值会被忽略,不会报错。 + +```javascript +let emptyObject = { ...null, ...undefined }; // 不报错 +```