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

修改iterator

This commit is contained in:
Ruan Yifeng 2015-02-27 14:59:18 +08:00
parent d37c6ff2a4
commit f1c2415227

View File

@ -62,13 +62,32 @@ it.next().value // '2'
总之所谓Iterator接口就是指调用这个接口会返回一个遍历器对象。该对象具备next方法每次调用该方法会返回一个具有value和done两个属性的新对象指向部署了Iterator接口的数据结构的一个成员。
如果使用TypeScript的写法遍历器接口、遍历器和遍历器返回值的规格可以描述如下。
```javascript
interface Iterable {
[System.iterator]() : Iterator,
}
interface Iterator {
next(value?: any) : IterationResult,
}
interface IterationResult {
value: any,
done: boolean,
}
```
### 默认的Iterator接口
Iterator接口的开发目的就是为所有数据结构提供了一种统一的访问机制即for...of循环见后文的介绍。当使用for...of循环遍历某种数据结构时该循环会自动去寻找Iterator接口。
ES6规定默认的Iterator接口部署在数据结构的Symbol.iterator属性。也就是说调用Symbol.iterator方法就会得到当前数据结构的默认遍历器。Symbol.iterator是一个表达式返回Symbol对象的iterator属性这是一个预定义好的、类型为Symbol的特殊值所以要放在方括号内请参考Symbol一节
在ES6中有三类数据结构原生具备Iterator接口数组、类似数组的对象、Set和Map结构。
在ES6中有三类数据结构原生具备Iterator接口数组、某些类似数组的对象、Set和Map结构。
```javascript
@ -202,6 +221,62 @@ obj[Symbol.iterator] = () => 1;
上面代码中变量obj的Symbol.iterator方法返回的不是遍历器因此报错。
### 调用默认iterator接口的场合
有一些场合会默认调用iterator接口即Symbol.iterator方法除了下文会介绍的for...of循环还有几个别的场合。
**1解构赋值**
对数组和Set结构进行解构赋值时会默认调用iterator接口。
```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'];
```
**2扩展运算符**
扩展运算符(...也会调用默认的iterator接口。
```javascript
// 例一
var str = 'hello';
[...str] // ['h','e','l','l','o']
// 例二
let arr = ['b', 'c'];
['a', ...arr, 'd']
// ['a', 'b', 'c', 'd']
```
上面代码的扩展运算符内部就调用iterator接口。
实际上这提供了一种简便机制可以将任何部署了iterator接口的对象转为对象。
```javascript
let arr = [...iterable];
```
**3其他场合**
以下场合也会用到默认的iterator接口可以查阅相关章节。
- yield*
- Array.from()
- Map(), Set(), WeakMap(), WeakSet()
- Promise.all(), Promise.race()
### 原生具备iterator接口的数据结构
《数组的扩展》一章中提到ES6对数组提供entries()、keys()和values()三个方法,就是返回三个遍历器。
@ -221,7 +296,7 @@ arrEntries === arrEntries[Symbol.iterator]()
上面代码中entries方法返回的是一个遍历器iterator本质上就是调用了`Symbol.iterator`方法。
字符串是一个类似数组的对象,因此也原生具有Iterator接口。
字符串是一个类似数组的对象也原生具有Iterator接口。
```javascript
@ -304,23 +379,30 @@ for (let x of obj) {
ES6中一个数据结构只要部署了Symbol.iterator方法就被视为具有iterator接口就可以用for...of循环遍历它的成员。也就是说for...of循环内部调用的是数据结构的Symbol.iterator方法。
for...of循环可以使用的范围包括数组、Set和Map结构、类似数组的对象比如arguments对象、DOM NodeList对象、后文的Generator对象以及字符串。
for...of循环可以使用的范围包括数组、Set和Map结构、某些类似数组的对象比如arguments对象、DOM NodeList对象、后文的Generator对象以及字符串。
### 数组
数组原生具备iterator接口。
数组原生具备iterator接口for...of循环本质上就是调用这个接口产生的遍历器可以用下面的代码证明
```javascript
const arr = ['red', 'green', 'blue'];
let iterator = arr[Symbol.iterator]();
for(let v of arr) {
console.log(v); // red green blue
}
for(let v of iterator) {
console.log(v); // red green blue
}
```
上面代码说明for...of循环可以代替数组实例的forEach方法。
上面代码的for...of循环的两种写法是等价的。
for...of循环可以代替数组实例的forEach方法。
```javascript
@ -457,6 +539,24 @@ for (let x of 'a\uD83D\uDC0A') {
```
并不是所有类似数组的对象都具有iterator接口一个简便的解决方法就是使用Array.from方法将其转为数组。
```javascript
let arrayLike = { length: 2, 0: 'a', 1: 'b' };
// 报错
for (let x of arrayLike) {
console.log(x);
}
// 正确
for (let x of Array.from(arrayLike)) {
console.log(x);
}
```
### 对象
对于普通的对象for...of结构不能直接使用会报错必须部署了iterator接口后才能使用。但是这样情况下for...in循环依然可以用来遍历键名。
@ -484,3 +584,5 @@ for (e of es6) {
```
上面代码表示对于普通的对象for...in循环可以遍历键名for...of循环会报错。
在对象上部署iterator接口的代码参见本章前面部分。