高下相倾,前后相随——iterator 与 for ... of 循环
iterator 是es6新提供的一种遍历器。本质上是一个接口,为各种不同的数据结构,提供统一的访问机制。
数据只要部署了iterator接口,便是可遍历的数据,标志是具有Symbol.iterator属性。换句话说,我们只要给数据部署这个属性,就可以将数据变为可遍历的数据。具体表现是数据能否用for...of 遍历。
原生具有iterator接口的数据类型:set, map, nodeList,string, arguments。这些数据类型是可以用for...of 遍历的。
// 数组的Symbol.iterator let arr = [1,2,4,65]; let iter = arr[Symbol.iterator](); console.log(iter.next()) // 一个对象如果要具备可被for of 循环调用的Iterator接口,就必须在Symbol.iterator的属性上部署遍历器生成的方法 class RangeIterator { constructor(start, stop){ this.value = start; this.stop = stop; } [Symbol.iterator](){return this} next () { let value = this.value; if (value < this.stop) { this.value ++ ; return {done: false, value: value} } else { return {done: true, value: undefined} } } } function range(start, stop) { return new RangeIterator(start, stop) } for (let v of range(0, 3)) { // console.log(v) } // 遍历器实现指针结构的例子 function obj(value) { this.value = value; this.next = null; } obj.prototype[Symbol.iterator] = function () { let iterator = {next: next}; let current = this; function next() { if (current) { let value = current.value; current = current.next; return {done: false, value: value}; } else { return {done: true} } } return iterator; } let one = new obj(1); let two = new obj(2); let three = new obj(3); one.text = two; two.next = three; for (let i of one) { console.log(i) } // 对于类数组的对象(存在键值名和length属性),部署iterator接口,有一个简单的方法,就是Symbol.iterator 方法直接引用数组的Iterator接口 NodeList.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator]; // 或者 NodeList.prototype[Symbol.iterator] = [][Symbol.iterator]; // 默认调用iterator的场合 /* * 解构赋值 * 扩展运算符 * yield* * 数组的遍历会调用遍历器的接口,所以任何接受数组为参数的场合,都会调用遍历器接口 * * */ // 字符串的iterator 接口 let str = 'adf'; let str_iterator = str[Symbol.iterator](); console.log(str_iterator.next(), str_iterator.next(), str_iterator.next())