Javascript設計模式之迭代器模式

擼狗吸貓發表於2019-04-12

前言:菜雞也有夢想,而我的夢想就是進一個真正的網際網路大廠。以前學習的時候沒有系統的整理,從今天開始要保持每週寫部落格的習慣,希望自己可以有所成長。為了培養程式設計思維,決定從設計模式開始寫起。我是通過讀《Javascript設計模式與開發實踐》來學習設計模式,並且將知識點和收穫記錄在部落格中。

此文僅記錄本人閱讀《JavaScript設計模式與開發實踐》的知識點與想法,感謝作者曾探大大寫出這麼好的一本書。如有冒犯,請聯絡本人:markcoder@outlook.com處理,請大家購買正版書籍。

1.迭代器模式介紹

迭代器模式是指提供一種方法順序訪問一個聚合物件中的各個元素,而又不需要暴露該物件 的內部表示。迭代器模式可以把迭代的過程從業務邏輯中分離出來,在使用迭代器模式之後,即 使不關心物件的內部構造,也可以按順序訪問其中的每個元素。
比如 jQuery 中的$.each 函式
$.each( [1, 2, 3], function( i, n ){ 
 console.log( '當前下標為: '+ i ); 
 console.log( '當前值為:' + n ); 
});
複製程式碼

2.程式碼示例

首先我們自己先實現一個迭代器
let each = function (arr, callback) {
    for (let i = 0; i < arr.length; i++) {
        callback.call(arr, i, arr[i])
    }
}

each([1, 2, 3], function (i, n) {
    console.log( '當前下標為: '+ i ); 
    console.log( '當前值為:' + n ); 
})
複製程式碼

3.內部迭代器和外部迭代器

迭代器可以分為內部迭代器和外部迭代器,它們有各自的適用場景。

3.1內部迭代器

內部迭代器就是內部已經定義好了迭代規則,它完全接手整個迭代過程,外部只需要一次初始呼叫。

內部迭代器在呼叫的時候非常方便,外界不用關心迭代器內部的實現,跟迭代器的互動也僅僅是一次初始呼叫,但這也剛好是內部迭代器的缺點。由於內部迭代器的迭代規則已經被提前規定,上面的 each 函式就無法同時迭代 2 個陣列了。

比如現在有個需求,要判斷 2 個陣列裡元素的值是否完全相等, 如果不改寫 each 函式本身 的程式碼,我們能夠入手的地方似乎只剩下 each 的回撥函式了,程式碼如下:

let compare = function (ary1, ary2) {
    if (ary1.length !== ary2.length) {
        throw new Error('兩個陣列不相等');
    }
    each(ary1, function (i, n) {
        if (n !== ary2[i]) {
            throw new Error('兩個陣列不相等');
        }
    })
    alert('兩個陣列相等');
}

compare([1, 2, 3], [2, 3, 4]); // throw new Error ( '兩個陣列不相等' );
複製程式碼

3.2外部迭代器

外部迭代器必須顯式地請求迭代下一個元素。

外部迭代器增加了一些呼叫的複雜度,但相對也增強了迭代器的靈活性,我們可以手工控制 迭代的過程或者順序。

let Iterator = function (arr) {
    let current = 0;
    
    let next = function () {
        current += 1;
    }
    
    let isDone = function () {
        return current >= arr.length;
    }
    
    let getCurrentItem = function () {
        return arr[current];
    }
    
    return {
        next,
        isDone,
        getCurrentItem
    }

}

let compare = function (iterator1, iterator2) {
    while (!iterator1.isDone() && !iterator2.isDone()) {
        if (iterator1.getCurrentItem() !== iterator2.getCurrentItem()) {
            throw new Error('兩個陣列不相等');
        }
        iterator1.next();
        iterator2.next();
    }
    alert('兩個陣列相等');
}

let iterator1 = Iterator([1, 2, 3]);
let iterator2 = Iterator([1, 2, 3]);

compare(iterator1, iterator2);
複製程式碼

外部迭代器雖然呼叫方式相對複雜,但它的適用面更廣,也能滿足更多變的需求。內部迭代 器和外部迭代器在實際生產中沒有優劣之分,究竟使用哪個要根據需求場景而定。

4.反向迭代器

let reverseEach = function (arr, callback) {
    for (let i = arr.length - 1; i>=0; i--) {
        callback.call(arr, i, arr[i]);
    }
}

reverseEach([1, 2, 3], function (index, item) {
    console.log(item); // 3 2 1
})
複製程式碼

5.終止迭代器

如果回撥函式的執行結果返回 false,則提前終止迴圈。
let each = function (arr, callback) {
    for (let i = 0; i < arr.length; i++) {
        if (callback.call(arr, i, arr[i]) === false) {
            break;
        }
    }
}

each( [ 1, 2, 3, 4, 5 ], function( i, n ){ 
    if ( n > 3 ){ // n 大於 3 的時候終止迴圈
        return false; 
    } 
    console.log( n ); // 分別輸出:1, 2, 3 
});
複製程式碼

相關文章