1. 程式人生 > 程式設計 >JS面試題之forEach能否跳出迴圈詳解

JS面試題之forEach能否跳出迴圈詳解

當年懵懂無知的我被問到這個問題時,腦袋一片空白,當然也沒答對,一直以來我對forEach都有一種錯誤的理解,由於它比原始的for迴圈簡潔許多,導致我一度認為那是為了方便書寫所創造出來的語法糖,在業務中也經常使用,但從沒考慮過這種方式存在的問題。

forEach使用說明

參考:https://developer.mozilla.org/en-US/docs/Web/javascript/Reference/Global_Objects/Array/forEach?v=example

arr.forEach(function callback(currentValue,index,array) {
    //your iterator
}[,thisArg]);
  • currentValue --- 當前處www.cppcns.com理的元素
  • index --- 當前處理元素的索引
  • array ---forEach應用的陣列

有一段提示寫到了在forEach中break和return的用法。原文如下:

There is no way to stop or break a forEach()loop other than by throwing an exception. If you need such behavior,theforEach()method is the wrong tool. Use a plain loop instead. If you are testing the array elements for a predicate and need a Boolean return value,you can useevery() or

some() instead. If available,the new methodsfind() or findIndex() can be used for early termination upon true predicates as well.

意思就是說在forEach中使用break和return是錯誤的,如果希望使用break或者return請使用every或者some函式。

那麼回到標題,首先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為每個陣列元素執行一次你所提供的函式。到這裡我的思路逐漸明朗,官方文件也有這麼一段話:

除丟擲異常之外,沒有其他方法可以停止或中斷迴圈。如果您需要這種行為www.cppcns.com,則該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
};

當然,使用try-catch包裹時,當迴圈體過大效能會隨之下降,這是無法避免的,所以丟擲異常並不是解決forEach問題的銀彈,我們迴歸到開頭寫的那段虛擬碼,我們對它進行一些優化,在真正的for迴圈中加入對傳入函式的判斷:

Array.prototype.forEach = function (fn) {
    for (let i = 0; i < this.length; i++) {
        let ret = fn(this[i],this);
        if (typeof ret !== "undefined" && (ret == null || ret == false)) break;
    }
}

這樣的話自然就能根據return值來進行迴圈跳出啦:

let arr = [0,4];

arr程式設計客棧.f程式設計客棧orEach(element => {
    if (element === 'stop') return false
    console.log(element); // 輸出 0 1 後面不輸出
});

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

文件中還提到forEach需要一個同步函式,也就是說在使用非同步函式或Promise作為回撥時會發生預期以外的結果,所以forEach還是需要慎用或者不要使用,當然這並不意味著專案開發中要一直用簡單的for迴圈去完成一切事情,我們可以在遍歷陣列時使用for..of..,在遍歷物件時使用for..in..,而官方也在forEach文件下列舉了其它一些工具函式:

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

根據不同的業務場景,選擇使用對應的工具函式來更有效地處理業務邏輯,至於forEach,我想就從此相忘於江湖吧。

總結

到此這篇關於js面試題之forEach能否跳出迴圈的文章就程式設計客棧介紹到這了,更多相關JS forEach跳出迴圈內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!