Найти тему
Nuances of programming

Почему нельзя прерывать цикл forEach в JavaScript

Оглавление

Источник: Nuances of Programming

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

-2

MDN знает всё

Как отмечает MDN:

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

Звучит весьма категорично. Однако это правда: важно знать, какой инструмент выбрать.

Перед тем, как разобраться, почему нельзя прерывать forEach(), давайте рассмотрим, что такое цикл и откуда появился forEach().

Что такое цикл

Циклы в программировании решают очень распространённую задачу: запускать тот же самый код для всех данных. Проще говоря:

Повторение того же кода снова и снова (в цикле), пока мы не достигнем конечного состояния.

Задача

Для сравнения решим задачу, используя различные виды циклов. Вот она: сравнить два массива и посмотреть, совпадают ли их элементы.

Вот данные, которые мы будем сравнивать:

const jedis = ["Anakin","Luke"]
const sith = ["Palpatine", "Anakin"]

У нас есть два массива, оба с парой имён. В обоих списках есть Энакен. Это простейшая задача, однако она не так далека от того, которую я решал на собеседовании.

Путь

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

Традиционный цикл for

Если вы когда-либо проходили курс по программированию, вы знакомы со старым добрым циклом for. Долгое время он был полезным инструментом для программистов, да и сейчас полезен. Давайте решим нашу задачу с его помощью:

Цикл for предлагает весьма удобный способ выхода, если он удовлетворяет выбранному условию, что чрезвычайно полезно при циклической обработке большого количества данных. Он также был очень полезен в решении некоторых задач Проекта Эйлера, особенно этой.

Альтернативный путь

forEach() был представлен в спецификации в 2009 году наряду с прочими достоинствами ES5. Он служит удобным методом написания чистого кода, который легко перебирает элементы массива.

Что он делает?

Цикл forEach() — это функция, запускающая другую функцию (обратный вызов) для каждого элемента массива. Мы определяем, что происходит в этой функции обратного вызова. JS принимает три параметра для этой функции:

  • элемент массива;
  • индекс элемента;
  • массив полностью.

Давайте используем цикл forEach() для решения нашей задачи. Я включил все три параметра в функцию, но используем мы только первый — элемент, который я назвал jedi.

Наше решение по сути делает то же самое. Единственное отличие в том, что код продолжает работать, пока не достигнет конца массива jedis. Навряд ли для такого маленького массива будет видна разница в производительности.

Но почему?

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

Из-за этого выражения break или continue также являются не допустимыми.

Другие пути

Существует довольно много различных циклов. Все они имеют различное применение, и я рекомендую ознакомиться с каждым из них. Вам не всегда нужен именно цикл forEach().

-3

forEach() или map()

Вероятно, наиболее распространёнными методами в руководствах являются forEach() и map(). Самое существенное различие между ними в том, что map возвращает новый массив, а forEach() — нет.

Традиционные циклы

Цикл while

Методы массива

Array.forEach(), Array.map(), Array.filter(), Array.reduce(), Array.reduceRight(), Array.every(), Array.some(), Array.indexOf(), Array.lastIndexOf(), Array.find(), Array.findIndex()

Повторяемые циклы объектов (включая массивы)

for in, for of

Вот путь

-4

Как упоминалось ранее, в документации MDN, выбор правильного инструмента крайне важен для успеха. На первый взгляд количество вариантов ошеломляет, но мне нравится подход: “если инструмент работает, значит, он подходит”.

Вы можете рефакторить свой код до посинения, но будете просто тратить время вместо того, чтобы создавать. На собеседовании я использовал правильный инструмент, но неправильным способом. Если бы я помнил, что цикл forEach() нельзя прервать, всё могло бы сложиться иначе ??‍♂️.

Хорошего кодинга!

Читайте также:

Читайте нас в Telegram, VK

Перевод статьи Jared Nutt: Why you can’t break a forEach loop in JavaScript