JavaScript 原有的表示“ 集合” 的数据结构, 主要是数组( Array) 和对象( Object), ES6 又添加了 Map 和 Set。 这样就有了四种数据集合, 用户还可以组合使用它们, 定义自己的数据结构, 比如数组的成员是 Map, Map 的成员是对象。 这样就需要一种统一的接口机制, 来处理所有不同的数据结构。
遍历器( Iterator) 就是这样一种机制。 它是一种接口, 为各种不同的数据结构提供统一的访问机制。 任何数据结构只要部署 Iterator 接口, 就可以完成遍历操作( 即依次处理该数据结构的所有成员)。
Iterator 的作用有三个:
- 为各种数据结构, 提供一个统一的、 简便的访问接口
- 使得数据结构的成员能够按某种次序排列
- ES6 创造了一种新的遍历命令for…of循环, Iterator 接口主要给for…of提供服务
Iterator 的遍历过程:
- 创建一个指针对象, 指向当前数据结构的起始位置。 也就是说, 遍历器对象本质上, 就是一个指针对象
- 第一次调用指针对象的next方法, 将指针指向数据结构的第一个成员
- 第二次调用指针对象的next方法, 指针就指向数据结构的第二个成员
- 不断调用指针对象的next方法, 直到它指向数据结构的结束位置
每一次调用next方法, 都会返回数据结构的当前成员的信息。 具体来说, 就是返回一个包含value和done两个属性的对象。 其中, value属性是当前成员的值, done属性是一个布尔值, 表示遍历是否结束。
var it = makeIterator(['a', 'b']);
it.next() // { value: "a", done: false }
it.next() // { value: "b", done: false }
it.next() // { value: undefined, done: true }
function makeIterator(array) {
var nextIndex = 0;
return {
next: function() {
return nextIndex < array.length ? {
value: array[nextIndex++],
done: false
} : {
value: undefined,
done: true
};
}
};
}
在ES6中,有些数据结构原生具备Iterator接口(比如数组),即不用任何处理,就可以被for…of循环遍历,有些就不行(比如对象)。原因在于,这些数据结构原生部署了Symbol.iterator属性,另外一些数据结构没有。凡是部署了Symbol.iterator属性的数据结构,就称为部署了遍历器接口。调用这个接口,就会返回一个遍历器对象。
在 ES6 中, 有三类数据结构原生具备 Iterator 接口: 数组、 某些类似数组的对象、 Set 和 Map 结构。
let arr = ['a', 'b', 'c'];
let iter = arr[Symbol.iterator]();
iter.next() // { value: 'a', done: false }
iter.next() // { value: 'b', done: false }
iter.next() // { value: 'c', done: false }
iter.next() // { value: undefined, done: true }
上面代码中, 变量arr是一个数组, 原生就具有遍历器接口, 部署在arr的Symbol.iterator属性上面。 所以, 调用这个属性, 就得到遍历器对象。
下面是类似数组的对象调用数组的Symbol.iterator方法的例子
let iterable = {
0: 'a',
1: 'b',
2: 'c',
length: 3,
[Symbol.iterator]: Array.prototype[Symbol.iterator]
};
for (let item of iterable) {
console.log(item); // 'a', 'b', 'c'
}
上面提到, 原生就部署 Iterator 接口的数据结构有三类, 对于这三类数据结构, 不用自己写遍历器生成函数,for…of循环会自动遍历它们。 除此之外, 其他数据结构( 主要是对象) 的 Iterator 接口, 都需要自己在Symbol.iterator属性上面部署, 这样才会被for…of循环遍历。
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 };
}
}
};
}
};
for(let item of obj){
console.log(item); //'hello','world'
}
调用 Iterator 接口的场合
(1)解构赋值对数组和 Set 结构进行解构赋值时, 会默认调用Symbol.iterator方法
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)扩展运算符
// 例一
var str = 'hello';
[...str] // ['h','e','l','l','o']
// 例二
let arr = ['b', 'c'];
['a', ...arr, 'd']
// ['a', 'b', 'c', 'd']
(3)yield *
yield * 后面跟的是一个可遍历的结构, 它会调用该结构的遍历器接口
let generator = function*() {
yield 1;
yield * [2, 3, 4];
yield 5;
};
var iterator = generator();
iterator.next() // { value: 1, done: false }
iterator.next() // { value: 2, done: false }
iterator.next() // { value: 3, done: false }
iterator.next() // { value: 4, done: false }
iterator.next() // { value: 5, done: false }
iterator.next() // { value: undefined, done: true }
(4)字符串的 Iterator 接口,字符串是一个类似数组的对象, 也原生具有 Iterator 接口
var someString = "hi";
typeof someString[Symbol.iterator]
// "function"
var iterator = someString[Symbol.iterator]();
iterator.next() // { value: "h", done: false }
iterator.next() // { value: "i", done: false }
iterator.next() // { value: undefined, done: true }
引自:
http://www.cnblogs.com/zczhangcui/p/6502836.html
http://blog.csdn.net/qq_30100043/article/details/53463471