设计模式 迭代器模式
迭代器模式:顺序访问一个集合(顺序访问就要求是有序的)。使用者无需知道集合的内部结构(封装)
<body> <div id="div1"> <p>jquery each</p> <p>jquery each</p> <p>jquery each</p> </div> <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); }) </script> </body>
这三种数据结构都是不一样的,但是他们都有一个特点就是他们都很清楚这个数据结构是什么样子的,那么我们能不能写一个函数,同时支持这三种遍历
<body> <div id="div1"> <p>jquery each</p> <p>jquery each</p> <p>jquery each</p> </div> <script> var arr = [1, 2, 3]; var nodeList = document.getElementsByTagName('p'); var $p = $('p'); function each(data) { var $data = $(data); // 生成迭代器 $data.each(function(key, val){ console.log(key, val) }) } // 顺序遍历有序集合 // 使用这不必知道集合的内部结构 each(arr); each(nodeList); each($p); </script> </body>
都转成jquery对象。
uml类图
代码
class Iterator { constructor(container) { this.list = container.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); } } // 测试代码 var arr = [1,2,3,4,5,6,7,8] let container = new Container(arr); let iterator = container.getIterator(); while(iterator.hasNext()) { console.log(iterator.next()) }
场景:ES6 Iterator
ES6 Iterator 为何存在?因为迭代器模式是常用的设计模式,所以存在肯定是合理的,es6 语法中,有序集合的数据类型已经有很多,而且还可以自己定义更多。必须有一种机制去统一他们。
比如Array, Map, Set, String, TypedArray, arguments, NodeList。如果要对这些进行遍历,需要有一个统一对遍历接口来遍历所有数据类型(注意object不是有序集合)
ES6 Iterator 是什么?以上数据类型,都可以通过 Iterator实现。都有[Symbol.iterator]属性。属性值是函数,执行函数返回一个迭代器。这个迭代器就有next方法可顺序迭代子元素。可运行Array.prototype[Symbol.iterator]来测试。
第一个返回一个函数,原始代码看不到,说明数组确实有这么一个属性,这个属性值是个函数
执行这个函数,返回一个迭代器。
迭代器有个next方法,他没有hasNext,通过next里面对done判断后面是否还有值
代码
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) } } } var arr = [1,2,3,4,5,6] each(arr);
Symbol.iterator并不是人人都知道,也不是每个人都需要封装一个each方法,因此有了for...of 语法,for...of是针对带有遍历器特性的对象,也就是 data[Symbol.iterator]有值。
function each(data) { for(let item of data) { console.log(item); } } var arr = [1,2,3,4,5,6] each(arr);
设计原则验证
迭代器对象和目标对象分离,迭代器将使用者与目标对象隔离开,符合开放封闭原则