From 38adc8e8ebb140b2cbb9523f021000f8cfc8e471 Mon Sep 17 00:00:00 2001 From: Ruan Yifeng Date: Sun, 28 Dec 2014 23:34:33 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9symbol?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/generator.md | 48 +++++++++++++++++++++++--- docs/iterator.md | 28 ++++++++++++++- docs/object.md | 87 ++++++++++++++++++++++++++++++++++++++++++----- docs/reference.md | 1 + 4 files changed, 149 insertions(+), 15 deletions(-) diff --git a/docs/generator.md b/docs/generator.md index 22a4005..d913c81 100644 --- a/docs/generator.md +++ b/docs/generator.md @@ -487,15 +487,53 @@ function* numbers() { ### (2)控制流管理 -总结一下,如果某个操作非常耗时,可以把它拆成N步。 +如果有一个多步操作非常耗时,采用回调函数,可能会写成下面这样。 + +```javascript + +step1(function (value1) { + step2(value1, function(value2) { + step3(value2, function(value3) { + step4(value3, function(value4) { + // Do something with value4 + }); + }); + }); +}); + +``` + +采用Promise改写上面的代码。 + +```javascript + +Q.fcall(step1) +.then(step2) +.then(step3) +.then(step4) +.then(function (value4) { + // Do something with value4 +}, function (error) { + // Handle any error from step1 through step4 +}) +.done(); + +``` + +上面代码已经把回调函数,改成了直线执行的形式。Generator函数可以进一步改善代码运行流程。 ```javascript function* longRunningTask() { - yield step1(); - yield step2(); - // ... - yield stepN(); + try { + var value1 = yield step1(); + var value2 = yield step2(value1); + var value3 = yield step3(value2); + var value4 = yield step4(value3); + // Do something with value4 + } catch (e) { + // Handle any error from step1 through step4 + } } ``` diff --git a/docs/iterator.md b/docs/iterator.md index 5fa15b1..d63d61c 100644 --- a/docs/iterator.md +++ b/docs/iterator.md @@ -67,7 +67,33 @@ class MySpecialTree { ``` -上面代码是一个类部署Iterator接口的写法。`Symbol.iterator`是一个表达式,返回一个Symbol对象的iterator属性,这是一个类型为Symbol的特殊值,所以要放在方括号内。这里要注意,@@iterator的键名是`Symbol.iterator`,该方法执行后,返回一个当前对象的遍历器。 +上面代码是一个类部署Iterator接口的写法。`Symbol.iterator`是一个表达式,返回Symbol对象的iterator属性,这是一个预定义好的、类型为Symbol的特殊值,所以要放在方括号内(请参考Symbol一节)。这里要注意,@@iterator的键名是`Symbol.iterator`,键值是一个方法(函数),该方法执行后,返回一个当前对象的遍历器。 + +下面是为对象添加Iterator接口的例子。 + +```javascript + +let obj = { + data: [ 'hello', 'world' ], + [Symbol.iterator]() { + const self = this; + let index = 0; + return { + next() { + if (index < self.data.length) { + return { + value: self.data[index++], + done: false + }; + } else { + return { value: undefined, done: true }; + } + } + }; + } +}; + +``` 《数组的扩展》一章中提到,ES6对数组提供entries()、keys()和values()三个方法,就是返回三个遍历器。 diff --git a/docs/object.md b/docs/object.md index 60986c8..8a030e6 100644 --- a/docs/object.md +++ b/docs/object.md @@ -305,7 +305,20 @@ Object.getPrototypeOf(obj) ## Symbol -ES6引入了一种新的原始数据类型Symbol。它通过Symbol函数生成。 +ES6引入了一种新的原始数据类型Symbol,表示独一无二的ID。它通过Symbol函数生成。 + +```javascript + +let symbol1 = Symbol(); + +typeof symbol +// "symbol" + +``` + +上面代码中,变量symbol1就是一个独一无二的ID。typeof运算符的结果,表明变量symbol1是Symbol数据类型,而不是字符串之类的其他类型。 + +Symbol函数可以接受一个字符串作为参数,表示Symbol实例的名称。 ```javascript @@ -314,14 +327,33 @@ var mySymbol = Symbol('Test'); mySymbol.name // Test -typeof mySymbol -// "symbol" +``` + +上面代码表示,Symbol函数的字符串参数,用来指定生成的Symbol的名称,可以通过name属性读取。之所以要新增name属性,是因为键名是Symbol类型,而有些场合需要一个字符串类型的值来指代这个键。 + +注意,Symbol函数前不能使用new命令,否则会报错。这是因为生成的Symbol是一个原始类型的值,不是对象。 + +Symbol类型的值不能与其他类型的值进行运算,会报错。 + +```javascript + +var sym = Symbol('My symbol'); +'' + sym +// TypeError: Cannot convert a Symbol value to a string ``` -上面代码表示,Symbol函数接受一个字符串作为参数,用来指定生成的Symbol的名称,可以通过name属性读取。typeof运算符的结果,表明Symbol是一种单独的数据类型。 +但是,Symbol类型的值可以转为字符串。 -注意,Symbol函数前不能使用new命令,否则会报错。这是因为生成的Symbol是一个原始类型的值,不是对象。 +```javascript + +String(sym) +// 'Symbol(My symbol)' + +sym.toString() +// 'Symbol(My symbol)' + +``` symbol的最大特点,就是每一个Symbol都是不相等的,保证产生一个独一无二的值。 @@ -331,6 +363,10 @@ let w1 = Symbol(); let w2 = Symbol(); let w3 = Symbol(); +w1 === w2 // false +w1 === w3 // false +w2 === w3 // false + function f(w) { switch (w) { case w1: @@ -346,18 +382,27 @@ function f(w) { 上面代码中,w1、w2、w3三个变量都等于`Symbol()`,但是它们的值是不相等的。 -由于这种特点,Symbol类型适合作为标识符,用于对象的属性名,保证了属性名之间不会发生冲突。如果一个对象由多个模块构成,这样就不会出现同名的属性。另一种用途是,可以防止属性值被不小心修改。 +由于这种特点,Symbol类型适合作为标识符,用于对象的属性名,保证了属性名之间不会发生冲突。如果一个对象由多个模块构成,这样就不会出现同名的属性,也就防止了键值被不小心改写或覆盖。Symbol类型还可以用于定义一组常量,防止它们的值发生冲突。 ```javascript -var a = {}; var mySymbol = Symbol(); +// 第一种写法 +var a = {}; a[mySymbol] = 'Hello!'; -//另一种写法 +// 第二种写法 +var a = { + [mySymbol]: 123 +}; + +// 第三种写法 +var a = {}; Object.defineProperty(a, mySymbol, { value: 'Hello!' }); +a[mySymbol] // "Hello!" + ``` 上面代码通过方括号结构和Object.defineProperty两种方法,将对象的属性名指定为一个Symbol值。 @@ -387,6 +432,15 @@ a.size // 1 ``` +为Symbol函数添加一个参数,就可以引用了。 + +```javascript + +let a = Map(); +a.set(Symbol('my_key'), 'Noise'); + +``` + 如果要在对象内部使用Symbol属性名,必须采用属性名表达式。 ```javascript @@ -411,7 +465,7 @@ let obj = { ``` -Symbol类型作为属性名,不会出现在for...in循环中,也不会被Object.getOwnPropertyNames方法返回,但是有一个对应的Object.getOwnPropertySymbols方法,以及Object.getOwnPropertyKeys方法都可以获取Symbol属性名。 +Symbol类型作为属性名,不会出现在for...in循环中,也不会被Object.keys()、Object.getOwnPropertyNames()返回,但是有一个对应的Object.getOwnPropertySymbols方法,以及Object.getOwnPropertyKeys方法都可以获取Symbol属性名。 ```javascript @@ -433,6 +487,21 @@ Object.getOwnPropertySymbols(obj) 上面代码中,使用Object.getOwnPropertyNames方法得不到Symbol属性名,需要使用Object.getOwnPropertySymbols方法。 +Reflect.ownKeys方法返回所有类型的键名。 + +```javascript + +let obj = { + [Symbol('my_key')]: 1, + enum: 2, + nonEnum: 3 +}; + +Reflect.ownKeys(obj) +// [Symbol(my_key), 'enum', 'nonEnum'] + +``` + ## Proxy 所谓Proxy,可以理解成在目标对象之前,架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。 diff --git a/docs/reference.md b/docs/reference.md index 1f61d8b..d8402bb 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -34,6 +34,7 @@ - Dmitry Soshnikov, [ES6 Notes: Default values of parameters](http://dmitrysoshnikov.com/ecmascript/es6-notes-default-values-of-parameters/): 介绍参数的默认值 - Mozilla Developer Network, [WeakSet](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakSet):介绍WeakSet数据结构 - Mathias Bynens, [Unicode-aware regular expressions in ES6](https://mathiasbynens.be/notes/es6-unicode-regex): 详细介绍正则表达式的u修饰符 +- Axel Rauschmayer, [Symbols in ECMAScript 6](http://www.2ality.com/2014/12/es6-symbols.html): Symbol简介 ## Iterator和Generator