1
0
mirror of https://github.com/ruanyf/es6tutorial.git synced 2025-05-24 18:32:22 +00:00

edit iterator

This commit is contained in:
Ruan Yifeng 2015-05-03 13:21:24 +08:00
parent 13df0a4f29
commit e39ea78257
2 changed files with 113 additions and 21 deletions

View File

@ -41,7 +41,7 @@ it.next() // { value: undefined, done: true }
function idMaker(){
var index = 0;
return {
next: function(){
return {value: index++, done: false};
@ -85,7 +85,7 @@ interface IterationResult {
Iterator接口的开发目的就是为所有数据结构提供了一种统一的访问机制即for...of循环见后文的介绍。当使用for...of循环遍历某种数据结构时该循环会自动去寻找Iterator接口。
ES6规定默认的Iterator接口部署在数据结构的Symbol.iterator属性。也就是说调用Symbol.iterator方法就会得到当前数据结构的默认遍历器。Symbol.iterator是一个表达式返回Symbol对象的iterator属性这是一个预定义好的、类型为Symbol的特殊值所以要放在方括号内请参考Symbol一节
ES6规定默认的Iterator接口部署在数据结构的Symbol.iterator属性或者一个数据结构只要具有Symbol.iterator属性就可以认为是“可遍历的”iterable。也就是说调用Symbol.iterator方法就会得到当前数据结构的默认遍历器。Symbol.iterator是一个表达式返回Symbol对象的iterator属性这是一个预定义好的、类型为Symbol的特殊值所以要放在方括号内请参考Symbol一节
在ES6中有三类数据结构原生具备Iterator接口数组、某些类似数组的对象、Set和Map结构。
@ -113,7 +113,7 @@ iter.next() // { value: undefined, done: true }
class MySpecialTree {
// ...
[Symbol.iterator]() {
[Symbol.iterator]() {
// ...
return theIterator;
}
@ -131,11 +131,11 @@ function Obj(value){
}
Obj.prototype[Symbol.iterator] = function(){
var iterator = {
next: next
};
var current = this;
function next(){
@ -221,6 +221,20 @@ obj[Symbol.iterator] = () => 1;
上面代码中变量obj的Symbol.iterator方法返回的不是遍历器因此报错。
有了遍历器接口数据结构就可以用for...of循环遍历详见下文也可以使用while循环遍历。
```javascript
var $iterator = ITERABLE[Symbol.iterator]();
var $result = $iterator.next();
while (!$result.done) {
var x = $result.value;
// ...
$result = $iterator.next();
}
```
上面代码中ITERABLE代表某种可遍历的数据结构$iterator是它的遍历器。遍历器每次移动指针next方法都检查一下返回值的done属性如果遍历还没结束就移动遍历器的指针到下一步next方法不断循环。
### 调用默认iterator接口的场合
有一些场合会默认调用iterator接口即Symbol.iterator方法除了下文会介绍的for...of循环还有几个别的场合。
@ -232,10 +246,10 @@ obj[Symbol.iterator] = () => 1;
```javascript
let set = new Set().add('a').add('b').add('c');
let [x,y] = set;
// x='a'; y='b'
let [first, ...rest] = set;
// first='a'; rest=['b','c'];
@ -286,7 +300,7 @@ let arr = [...iterable];
var arr = [1, 5, 7];
var arrEntries = arr.entries();
arrEntries.toString()
arrEntries.toString()
// "[object Array Iterator]"
arrEntries === arrEntries[Symbol.iterator]()
@ -301,7 +315,7 @@ arrEntries === arrEntries[Symbol.iterator]()
```javascript
var someString = "hi";
typeof someString[Symbol.iterator]
typeof someString[Symbol.iterator]
// "function"
var iterator = someString[Symbol.iterator]();
@ -323,7 +337,7 @@ var str = new String("hi");
[...str] // ["h", "i"]
str[Symbol.iterator] = function() {
return {
return {
next: function() {
if (this._first) {
this._first = false;
@ -336,7 +350,7 @@ str[Symbol.iterator] = function() {
};
};
[...str] // ["bye"]
[...str] // ["bye"]
str // "hi"
```
@ -352,9 +366,9 @@ str // "hi"
var myIterable = {};
myIterable[Symbol.iterator] = function* () {
yield 1;
yield 2;
yield 3;
yield 1;
yield 2;
yield 3;
};
[...myIterable] // [1, 2, 3]
@ -375,9 +389,17 @@ for (let x of obj) {
```
### return()throw()
遍历器除了具有next方法必备还可以具有return方法和throw方法可选
for...of循环如果提前退出通常是因为出错或者有break语句或continue语句就会调用return方法。如果一个对象在完成遍历前需要清理或释放资源就可以部署return方法。
throw方法主要是配合Generator函数使用一般的遍历器用不到这个方法。请参阅《Generator函数》的章节。
## for...of循环
ES6中一个数据结构只要部署了Symbol.iterator方法就被视为具有iterator接口就可以用for...of循环遍历它的成员。也就是说for...of循环内部调用的是数据结构的Symbol.iterator方法。
ES6借鉴C++、Java、C#和Python语言引入了for...of循环作为遍历所有数据结构的统一的方法。一个数据结构只要部署了`Symbol.iterator`方法就被视为具有iterator接口就可以用for...of循环遍历它的成员。也就是说for...of循环内部调用的是数据结构的`Symbol.iterator`方法。
for...of循环可以使用的范围包括数组、Set和Map结构、某些类似数组的对象比如arguments对象、DOM NodeList对象、后文的Generator对象以及字符串。
@ -391,11 +413,11 @@ const arr = ['red', 'green', 'blue'];
let iterator = arr[Symbol.iterator]();
for(let v of arr) {
console.log(v); // red green blue
console.log(v); // red green blue
}
for(let v of iterator) {
console.log(v); // red green blue
console.log(v); // red green blue
}
```
@ -471,11 +493,16 @@ for (let pair of map) {
// ['a', 1]
// ['b', 2]
for (let [key, value] of map) {
console.log(key + ' : ' + value);
}
// a : 1
// b : 2
```
### 计算生成的数据结构
ES6的数组、Set、Map都部署了以下三个方法调用后都返回遍历器。
有些数据结构是在现有数据结构的基础上,计算生成的。比如,ES6的数组、Set、Map都部署了以下三个方法调用后都返回遍历器。
- entries() 返回一个遍历器,用来遍历 [键名, 键值] 组成的数组。对于数组键名就是索引值对于Set键名与键值相同。Map结构的iterator接口默认就是调用entries方法。
- keys() 返回一个遍历器,用来遍历所有的键名。
@ -546,12 +573,12 @@ for (let x of 'a\uD83D\uDC0A') {
let arrayLike = { length: 2, 0: 'a', 1: 'b' };
// 报错
for (let x of arrayLike) {
for (let x of arrayLike) {
console.log(x);
}
// 正确
for (let x of Array.from(arrayLike)) {
for (let x of Array.from(arrayLike)) {
console.log(x);
}
@ -585,4 +612,68 @@ for (e of es6) {
上面代码表示对于普通的对象for...in循环可以遍历键名for...of循环会报错。
在对象上部署iterator接口的代码参见本章前面部分。
一种解决方法是,使用`Object.keys`方法将对象的键名生成一个数组,然后遍历这个数组。
```javascript
for (var key of Object.keys(someObject)) {
console.log(key + ": " + someObject[key]);
}
```
在对象上部署iterator接口的代码参见本章前面部分。一个方便的方法是将数组的`Symbol.iterator`属性,直接赋值给其他对象的`Symbol.iterator`属性。比如想要让for...of循环遍历jQuery对象只要加上下面这一行就可以了。
```javascript
jQuery.prototype[Symbol.iterator] =
Array.prototype[Symbol.iterator];
```
### 与其他遍历语法的比较
以数组为例JavaScript提供多种遍历语法。最原始的写法就是for循环。
```javascript
for (var index = 0; index < myArray.length; index++) {
console.log(myArray[index]);
}
```
这种写法比较麻烦因此数组提供内置的forEach方法。
```javascript
myArray.forEach(function (value) {
console.log(value);
});
```
这种写法的问题在于无法中途跳出forEach循环break命令或return命令都不能奏效。
for...in循环可以遍历数组的键名。
```javascript
for (var index in myArray) {
console.log(myArray[index]);
}
```
for...in循环有几个缺点。
1数组的键名是数字但是for...in循环是以字符串作为键名“0”、“1”、“2”等等。
2for...in循环不仅遍历数字键名还会遍历手动添加的其他键甚至包括原型链上的键。
3某些情况下for...in循环会以任意顺序遍历键名。
总之for...in循环主要是为遍历对象而设计的不适用于遍历数组。
for...of循环相比上面几种做法有一些显著的优点。
```javascript
for (let value of myArray) {
console.log(value);
}
```
- 有着同for...in一样的简洁语法但是没有for...in那些缺点。
- 不同用于forEach方法它可以与break、continue和return配合使用。
- 提供了遍历所有数据结构的统一操作接口。

View File

@ -76,6 +76,7 @@
- Harold Cooper, [Coroutine Event Loops in Javascript](http://syzygy.st/javascript-coroutines/): Generator用于实现状态机
- Ruslan Ismagilov, [learn-generators](https://github.com/isRuslan/learn-generators): 编程练习共6道题
- Kyle Simpson, [Iterating ES6 Numbers](http://blog.getify.com/iterating-es6-numbers/): 在数值对象上部署遍历器
- Steven Sanderson, [Experiments with Koa and JavaScript Generators](http://blog.stevensanderson.com/2013/12/21/experiments-with-koa-and-javascript-generators/): Generator入门介绍以Koa框架为例
## Promise对象