博客 / 詳情

返回

面試官問我 JS 中 foreach 能不能跳出循環

當年懵懂無知的我被問到這個問題時,腦袋一片空白,因為我一度認為forEach可能只是為了方便書寫所創造出來的語法糖,在業務代碼中也經常使用,但沒有思考過它存在的問題,本文旨在記錄自己的心路歷程,拋磚引玉,如果對你有所幫助那就更好啦。

那麼回到標題,首先forEach不能使用任何手段跳出循環的,為什麼呢?繼續往下看。

我們知道forEach接收一個函數,它一般有兩個參數,第一個是循環的當前元素,第二個是該元素對應的下標,手動實現一下偽代碼:

Array.prototype.myForEach = function (fn) {
    for (let i = 0; i < this.length; i++) {
        fn(this[i], i, this);
    }
}

forEach是不是真的這麼實現我無從考究,但是以上這個簡單的偽代碼確實滿足forEach的特性,而且也很明顯就是不能跳出循環,因為根本沒有辦法操作到真正的for循環體。

後來經過查閲文檔,發現官方對forEach的定義根本不是我認為的語法糖,它的標準説法是forEach為每個數組元素執行一次你所提供的函數。官方文檔也有這麼一段話:

除拋出異常之外,沒有其他方法可以停止或中斷循環。如果您需要這種行為,則該forEach()方法是錯誤的工具。

使用拋出異常來跳出foreach循環:

let arr = [0, 1, "stop", 3, 4];
try {
    arr.forEach(element => {
        if (element === "stop") {
            throw new Error("forEachBreak");
        }
        console.log(element); // 輸出 0 1 後面不輸出
    });
} catch (e) {
    console.log(e.message); // forEachBreak
};

那麼可不可以認為,forEach可以跳出循環,使用拋出異常就可以了?這點我認為仁者見仁智者見智吧,在forEach的設計中並沒有中斷循環的設計,而使用try-catch包裹時,當循環體過大性能會隨之下降,這是無法避免的,所以拋出異常可以作為一種中斷forEach的手段,但並不是為解決forEach問題而存在的銀彈。

再次迴歸到開頭寫的那段偽代碼,對它進行一些優化,在真正的for循環中加入對傳入函數的判斷:

// 為避免爭議此處不覆寫原有forEach函數
Array.prototype.myForEach = function (fn) {
    for (let i = 0; i < this.length; i++) {
        let ret = fn(this[i], i, this);
        if (typeof ret !== "undefined" && (ret == null || ret == false)) break;
    }
}

這樣的話就能根據return值來進行循環跳出啦:

let arr = [0, 1, "stop", 3, 4];

arr.myForEach(x => {
    if (x === 'stop') return false
    console.log(x); // 輸出 0 1 後面不輸出
});

// return即為continue:
arr.myForEach(x => {
    if (x === 'stop') return
    console.log(x); // 0 1 3 4
});

文檔中還提到forEach需要一個同步函數,也就是説在使用異步函數Promise作為回調時會發生預期以外的結果,所以forEach還是需要慎用。

當然,用簡單的for循環去完成一切事情也不失為一種辦法,代碼首先是寫給人看的,附帶在機器上運行的作用forEach在很多時候用起來更加順手,但也務必在理解JS如何設計這些工具函數的前提下來編寫我們的業務代碼。

我們可以在遍歷數組時使用for..of..,在遍歷對象時使用for..in..,而官方也在forEach文檔下列舉了其它一些工具函數,這裏不做過多展開:

Array.prototype.find()
Array.prototype.findIndex()
Array.prototype.map()
Array.prototype.filter()
Array.prototype.every()
Array.prototype.some()

如何根據不同的業務場景,選擇使用對應的工具函數來更有效地處理業務邏輯,才是我們真正應該思考的,或許這也是面試當中真正想考察的吧。

原文鏈接 https://juejin.cn/post/697197...

user avatar 1023 頭像 lanlanjintianhenhappy 頭像 ivyzhang 頭像 huishou 頭像 coderleo 頭像 _raymond 頭像 sunhengzhe 頭像 uncletong_doge 頭像 susouth 頭像 buxia97 頭像
10 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.