迭代器模式
顺序访问一个集合
使用者无需知道集合内部结构(封装)
jQuery 示例
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>Document</title> </head> <body> <p>jquery each</p> <p>jquery each</p> <p>jquery each</p> <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script> <script> var arr = [1, 2, 3]; var nodeList = document.getElementsByTagName("p"); var $p = $("p"); // 要对这三个变量进行遍历,需要写三个遍历方法 // 第一 arr.forEach(function(item) { console.log(item); }); // 第二 var i, length = nodeList.length; for (i = 0; i < length; i++) { console.log(nodeList[i]); } // 第三 $p.each(function(key, p) { console.log(key, p); }); // 如何能写出一个方法来遍历这三个对象呢 function each(data) { var $data = $(data); $data.each(function(key, p) { console.log(key, p); }); } each(arr); each(nodeList); each($p); </script> </body> </html>
传统 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); }
设计原则验证
- 迭代器对象和目标对象分离
- 迭代器将使用者与目标者对象隔离开
- 符合开放封闭原则
来源:https://www.cnblogs.com/ygjzs/p/12240147.html