Интервьюер спросил меня, может ли forEach в JS выйти из цикла

JavaScript

Когда я был в неведении и невежестве, когда мне задавали этот вопрос, в голове было пусто, потому что когда-то я думал, что forEach — это просто синтаксический сахар, созданный для удобства написания, и он часто использовался в бизнес-коде, но я не подумайте о его проблемах.Эта статья Цель состоит в том, чтобы записать ваше собственное ментальное путешествие, чтобы дать вам подсказку, если это поможет вам, это будет еще лучше.

Итак, вернемся к заголовку, прежде всего forEachНе могу использовать никакие средства, чтобы вырваться из циклаДа, инспектор, который хочет знать ответ на вопрос, может в это время прекратить чтение.

Зачем? Мы знаем, что forEach получает функцию, которая обычно имеет два параметра, первый — это текущий элемент цикла, а второй — индекс, соответствующий элементу.Вручную реализуем псевдокод:

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

Я не знаю, действительно ли forEach реализован таким образом, но приведенный выше простой псевдокод действительно удовлетворяет характеристикам forEach, а также очевидно, что он не может выскочить из цикла, потому что нет возможности оперировать настоящим для тела цикла.

Позже, ознакомившись с документацией, я обнаружил, что официальное определение forEach, на мой взгляд, не является синтаксическим сахаром.Его стандартное утверждение состоит в том, что forEach выполняет предоставленную вами функцию один раз для каждого элемента массива. В официальном документе также есть этот абзац:

Невозможно остановить или разорвать цикл, кроме создания исключения. Если вам нужно такое поведение, метод forEach() — неправильный инструмент.

Используйте исключение throw, чтобы выйти из цикла 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;
    }
}

Таким образом, цикл можно прервать в соответствии с возвращаемым значением:

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()

Как выбрать и использовать соответствующие функции инструмента для более эффективной обработки бизнес-логики в соответствии с различными бизнес-сценариями — это то, о чем мы действительно должны подумать, возможно, это то, что мы действительно хотим исследовать на собеседовании.