顺序访问一个集合
使用者无需知道集合内部结构(封装)
jQuery 示例
Documentjquery eachjquery eachjquery each
传统 UML 类图
javascript 中的 UML 类图
class Iterator { constructor(conatiner) { this.list = conatiner.list; this.index = 0; } next() { if (this.hasNext()) { return this.list[this.index++]; } return null; } hasNext() { if (this.index >= this.list.length) { return false; } return true; } } class Container { constructor(list) { this.list = list; } getIterator() { return new Iterator(this); } } // 测试代码 let container = new Container([1, 2, 3, 4, 5]); let iterator = container.getIterator(); while (iterator.hasNext()) { console.log(iterator.next()); }
使用场景
jQuery each
上面的 jQuery 代码就是
ES6 Iterator
ES6 Iterator 为何存在?
- es6 语法中,有序集合的数据类型已经有很多了
- Array Map Set String TypedArray argument Nodelist
- 需要有一个统一的遍历接口来遍历所有的数据类型
- (注意,object 不是有序集合,可以用 Map 代替)
es6 Interator 是什么?
- 以上数据类型,都有[Symbol.iterator]属性
- 属性值是函数,执行函数返回一个迭代器
- 这个迭代器就有 next 方法可以顺序迭代子元素
- 可运行 Array.prototype[Symbol.iterator]来测试
示例
let arr = [1, 2, 3, 4] let nodeList = document.getElementsByTagName('p') let m = new Map() m.set('a', 100) m.set('b', 200) function each(data) { // 生成遍历器 let iterator = data[Symbol.iterator]() console.log(iterator.next()) // 有数据时返回 {value: 1, done: false} console.log(iterator.next()) console.log(iterator.next()) console.log(iterator.next()) console.log(iterator.next()) // 没有数据时返回 {value: undefined, done: true} each(arr) each(nodeList) each(m)
上面代码改进
let arr = [1, 2, 3, 4]; let nodeList = document.getElementsByTagName("p"); let m = new Map(); m.set("a", 100); m.set("b", 200); function each(data) { // 生成遍历器 let iterator = data[Symbol.iterator](); let item = { done: false }; while (!item.done) { item = iterator.next(); if (!item.done) { console.log(item.value); } } } each(arr); each(nodeList); each(m);
es6 很聪明提供了for of
let arr = [1, 2, 3, 4]; let nodeList = document.getElementsByTagName("p"); let m = new Map(); m.set("a", 100); m.set("b", 200); function each(data) { for (let item of data) { console.log(item); } } each(arr); each(nodeList); each(m);
ES6 Interator 与 Generator
- Interator 的价值不限于上述几个类型的遍历
- 还有 Generator 函数的使用
- 即只要返回的数据符合 Interator 接口的要求
function* helloWorldGenerator() { yield "hello"; yield "world"; return "ending"; } var hw = helloWorldGenerator(); console.log(hw.next()); console.log(hw.next()); console.log(hw.next()); console.log(hw.next()); //输出 // { value: 'hello', done: false } // { value: 'world', done: false } // { value: 'ending', done: true } // { value: undefined, done: true }
function* foo() { yield 1; yield 2; yield 3; yield 4; yield 5; return 6; } for (let v of foo()) { console.log(v); }
设计原则验证
- 迭代器对象和目标对象分离
- 迭代器将使用者与目标者对象隔离开
- 符合开放封闭原则