本系列文章主要根據《JavaScript設計模式與開發實踐》整理而來,其中會加入了一些本身的思考。但願對你們有所幫助。jquery
js設計模式--單例模式es6
js設計模式--策略模式segmentfault
js設計模式--代理模式設計模式
迭代器模式是指提供一種方法順序訪問一個聚合對象中的各個元素,而又不須要暴露該對象的內部表示。迭代器模式能夠把迭代的過程從業務邏輯中分離出來,在使用迭代器模式以後,即便不關心對象的內部構造,也能夠按順序訪問其中的每一個元素。數組
JavaScript已經內置迭代器,如forEach Iterator等,再如jquery的$.eachapp
內部已經定義好了迭代規則,它徹底接手整個迭代過程,外部只須要一次初始調用
var each = function (ary, callback) { for (var i = 0; i < ary.length; i++) { callback(i, ary[i]) } } each([1, 2, 3, 4, 5], function (i, item) { console.log(i, item) })
優勢:內部迭代器在調用的時候很是方便,外界不用關心迭代器內部的實現,跟迭代器的交互也僅 僅是一次初始調用函數
缺點:因爲內部迭代器的迭代規則已經被提早規 定,上面的 each 函數就沒法同時迭代2個數組,以下代碼測試
var compare = function( ary1, ary2 ){ if ( ary1.length !== ary2.length ){ throw new Error ( 'ary1 和ary2 不相等' ); } each( ary1, function( i, n ){ if ( n !== ary2[ i ] ){ throw new Error ( 'ary1 和ary2 不相等' ); } }); alert ( 'ary1 和ary2 相等' ); }; compare( [ 1, 2, 3 ], [ 1, 2, 4 ] ); // throw new Error ( 'ary1 和ary2 不相等' );
外部迭代器必須顯式地請求迭代下一個元素
咱們模擬一個es6迭代器ui
var Iterator = function (ary) { this.ary = ary this.index = 0 } Iterator.prototype.isDone = function () { return this.index >= this.ary.length } Iterator.prototype.next = function () { if (!this.isDone()) { var res = this.ary[this.index] this.index++ return { value: res, done: this.isDone() } } } var a = new Iterator([1, 2, 3]) while (!a.isDone()) { console.log(a.next()) }
下面解決一下上面那個問題this
var a = new Iterator([1, 2, 3, 3]) var b = new Iterator([1, 2, 3]) function compare(iterator1, iterator2) { while (!iterator1.isDone() || !iterator2.isDone()) { if (iterator1.next().value !== iterator2.next().value) { return false } } return true } compare(a, b)
var getUploadObj = function () { try { return new ActiveXObject("TXFTNActiveX.FTNUpload"); } catch (e) { // IE 上傳控件 if (supportFlash()) { // supportFlash 函數未提供 var str = '<object type="application/x-shockwave-flash"></object>'; return $(str).appendTo($('body')); } else { var str = '<input name="file" type="file"/>'; // 表單上傳 return $(str).appendTo($('body')); } } };
缺點:第一是很難閱讀,第二是嚴重違反開閉原則
var getActiveUploadObj = function () { try { return new ActiveXObject("TXFTNActiveX.FTNUpload"); } catch (e) { return false; } }; var getFlashUploadObj = function () { if (supportFlash()) { // supportFlash 函數未提供 var str = '<object type="application/x-shockwave-flash"></object>'; return $(str).appendTo($('body')); }; return false; } var getFormUpladObj = function () { var str = '<input name="file" type = "file" class = "ui-file" / > '; // 表單上傳 return $(str).appendTo($('body')); } var iteratorUploadObj = function () { for (var i = 0, fn; fn = arguments[i++];) { var uploadObj = fn(); if (uploadObj !== false) { return uploadObj; } }; } var uploadObj = iteratorUploadObj(getActiveUploadObj, getFlashUploadObj, getFormUpladObj);
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()) }
咱們都知道Array、Map、Set、類對象(如arguments NodeList等)都有一個Symbol.iterator迭代方法,能夠經過如下方式取得
var a = [1,2,3] console.log(a[Symbol.iterator])
另外generator也會返回迭代器
function* gen() { yield 1 yield '1' } var a = gen() a.next()