#javascript #for-loop #foreach
#javascript #for-цикл #foreach
Вопрос:
Я узнал, что a for
выполняет итерацию по каждому элементу массива, даже если указанный регистр не существует, в то время как a forEach
пропускает несуществующие регистры.
Более того, при for
записи a должен быть указан счетчик (я не говорю об for...in
этом), в то время как a forEach
просто использует итератор функции.
Хорошо. Не могли бы вы ответить на четыре следующих вопроса, пожалуйста?
- Действительно ли a
forEach
пропускает случаи несуществующих массивов, а a —for
нет? forEach
Использует ли a счетчик intern (нам просто не нужно его писать)? Или это совершенно другой механизм, чем afor
?- В некоторых языках a
forEach
не проходит через массив в том же порядке, что и порядок массива. Как насчет JavaScript - Наконец, существуют ли другие различия между ними (исключая, конечно, грамматические / синтаксические)?
Комментарии:
1. чтение документов дало бы ответы на большинство ваших вопросов. forEach … для
Ответ №1:
for
Ключевое слово — это языковая конструкция, это самый быстрый и самый «сырой» способ перебора вещей. Он имеет три стиля:
-
C-стиль
for
:for ( initializer; condition; iterator ) { code... }
— это самая гибкая и проверенная временем версия. Чтобы выполнить итерацию по списку, вы начинаете перебирать все индексы списка от 0 до длины списка. Вы также можете перейти к любому другому, третьему и т.д. элементу. В большинстве случаев этого достаточно. -
Javascript
for-in
for (var key in object) { code ... }
— это хороший способ перебрать каждый ключ в объекте, например, для вывода всех значений объекта JSON. -
(ES2015) Javascript
for-of
:for (var item of collection) { code ... }
— этот новый и доступен в современных браузерах. Это позволяет вам пропускать индексы и счетчики и позволяет просматривать каждый элемент коллекции. (Скажем, каждый объект в списке продуктов.) Он делает то же самое, что и For в стиле C, но проще в использовании.
Однако forEach
функция специфична для Array
объектов в Javascript и позволяет запускать функцию для каждого элемента в массиве. Хорошо, если у вас есть служебная функция, которая делает всю работу за вас.
Вот как использовать все вышеперечисленные виды итераций:
// most plain kind of array with a length of 7
var myArray = [1, 2, 3, 4, 5, 6, undefined];
// a weird kind of array with no values between index 3 and 100
// its length is 102
var mySparseArray = [1, 2, 3, 4];
mySparseArray[100] = 5;
mySparseArray[101] = 6;
// 1. C-style for
// ** can control how index is incremented
// ** needs an extra variable to iterate with
for (var i = 0; i < myArray.length; i = 1) {
console.log(myArray[i]);
// logs 1, 2, 3, 4, 5, 6, undefined
}
for (var i = 0; i < mySparseArray.length; i = 1) {
console.log(myArray[i]);
// logs 1, 2, 3, 4, undefined, undefined, ... (up to index 100), 5, 6
}
// 2. for..in
// ** keys are iterated over in non-guaranteed order
// (you might get 2, "length", 1, 0, 3)
// ** all enumerable keys are included, that might include things other than indexes.
for (var key in myArray) {
console.log(myArray[key]);
// logs 1, 2, 3, 4, 5, 6
}
for (var key in mySparseArray) {
console.log(mySparseArray[key]);
// logs 1, 2, 3, 4, 5, 6
// this for-loop "thinks" the array is an object with numbers for keys
}
// 3. for..of
// ** only available in browsers with ES2015 support
// ** supports many other things than Arrays - TypedArrays, Iterators...
for (var item of myArray) {
console.log(item);
}
for (var item of mySparseArray) {
console.log(item);
// logs 1, 2, 3, 4, undefined, undefined, ... (up to index 100), 5, 6
}
// 4. forEach
// ** calls a function for each element (considered slow)
// ** supports only Arrays (unless you call it with Array.prototype.forEach.call)
function myCallback(element) {
console.log(element);
}
myArray.forEach(myCallback); // logs 1, 2, 3, 4, 5, 6
mySparseArray.forEach(myCallback); // logs 1, 2, 3, 4, 5, 6
Обязательно попробуйте их в консоли разработчика вашего браузера! Вы можете увидеть каждый из приведенных выше фрагментов кода в действии.
Обязательно проверяйте ссылку MDN на итерациях.
Комментарии:
1. Что касается пропуска, OP означает конкретно не существующие свойства, а не только те, у
undefined
которых есть значение. И.forEach
действительно пропускает их, попробуйте использовать разреженный массив.2.
length
не должно быть перечислимым, поэтому оно не повторяетсяfor...in
.
Ответ №2:
Итак, когда вы говорите о for
цикле, вы имеете в виду фактический for
цикл, а не for...in
(который не должен использоваться в массивах). Похоже, существует небольшое заблуждение, и позвольте мне начать с этого:
for
Цикл не предназначен для перебора массивов. Не то, чтобы вы не должны или это плохо, но это не его основная функция — он буквально просто зацикливается до тех пор, пока не будет выполнено условие, после чего он останавливается. Наиболее распространенным синтаксисом является for (var i =0; i < max; i )
тот, который хорошо подходит для цикла массива, но это не значит, что вы не можете иметь, скажем, for (var i = 100; Number.isInteger(i); i = i/2)
. Итак, с учетом сказанного, вот ответы на ваши вопросы:
1. forEach
Пропускает ли отсутствующие элементы в массиве?
Ответ: Да
forEach
это метод массива map
, и наряду с reduce
другими он пропускает неназначенные слоты. Это должно помочь в работе с разреженными массивами, например
var arr = [];
arr[5] = "five";
arr[7] = "seven";
arr[10] = "ten";
console.log("---using forEach---");
arr.forEach(function(item) {
console.log(item);
});
console.log("---using a for-loop---");
for (var i = 0; i < arr.length; i ) {
console.log(arr[i]);
}
Это простой пример, который иллюстрирует, почему вы можете захотеть использовать цикл разреженного массива — как вы можете видеть, вы получаете намного меньше выполнения кода. Вот немного более сложный:
var arr = [];
arr[5] = "five";
arr[42] = "the answer";
arr[9001] = "over nine thousand";
arr.forEach(function(item) {
console.log(item);
});
Прямой for
цикл будет выполняться (буквально) более девяти тысяч раз, когда все, что у вас есть, это три элемента.
Я должен кое-что уточнить здесь — сброшенные значения — это любые значения, которым вы ничего не присвоили. Назначение undefined
считается назначением по-прежнему:
var arr = [];
arr[5] = "five";
arr[7] = undefined;
arr[10] = "ten";
arr.forEach(function(item) {
console.log(item);
});
2. forEach
Использует ли внутренний счетчик
Ответ: да
Вы можете легко получить текущий результат, поскольку он передается в обратный вызов.
var arr = [];
arr[5] = "five";
arr[42] = "the answer";
arr[9001] = "over nine thousand";
arr.forEach(function(item, index) {
console.log(index, "-", item);
});
3. В каком порядке выполняется forEach
Ответ: начинается с нуля и идет в порядке возрастания
Вышеизложенное должно показать вам это. Вот еще один краткий пример:
var alphabet = ["a", "b", "c", "d", "e", "f", "g" ];
alphabet.forEach(function(letter, index) {
console.log(index, letter);
})
4. Различия между for
и forEach
Ответ: их сложно сравнивать
Различия между ними — это то, на что я ссылался в начале — for
это общий оператор цикла в JavaScript — вы можете использовать его для просмотра массивов, но вы можете использовать его и для других целей. forEach
, напротив, он специально привязан к массивам. Очень сложно реально сравнивать два, но если мы ограничимся только разговорами об их использовании в массивах, вот несколько моментов
for
- Вы можете выйти из цикла раньше, используя
break
orreturn
, поэтому вам не нужно перебирать весь массив - Вы можете управлять обходом массива, поэтому вы можете начать с конца и отсчитывать (
for (var i = arr.length; i >= 0; i--)
) или, возможно, даже вернуться назад или пропустить элементы (выполнениеi--
илиi = 2
внутри тела цикла) - Хорошо известен как механизм цикла, поскольку он используется во многих других языках
- /- Вы будете выполнять цикл по всей длине массива, даже для разреженных массивов.
- — Вы должны поддерживать счетчик циклов, даже если он вас не волнует.
forEach
- Хорошо работает с разреженными массивами
- Принимает обратные вызовы, поэтому вы можете повторно использовать функции, передавая их в
.forEach
вызов - Еще одним преимуществом вышесказанного является функциональная область для всего, что находится внутри тела обратного вызова (хотя с ES6
let
иconst
это имеет меньшее значение) - Идиоматический JavaScript
- /- Вы будете просматривать только существующие элементы в разреженном массиве
- — Невозможно завершить досрочно, хотя вы могли бы использовать
find
. - — У вас нет контроля над тем, как проходит массив.
PS: Почетное упоминание относится к for...of
Благодаря @Bergi я вспомнил кое-что, что хотел включить сюда:
Один цикл, который вы не упомянули, но который существует, — это for...of
цикл, который похож по синтаксису на for...in
цикл, но он предназначен для работы с массивами, а также с другими итеративными объектами. Это относительно новая конструкция ( forEach
по крайней мере, более новая), как указано в спецификациях ES6, поэтому широкая веб-поддержка может отсутствовать, но это альтернатива обоим из вышеперечисленных. Он довольно прост в использовании:
var arr = [];
arr[5] = "five";
arr[7] = "seven";
arr[10] = "ten";
for (item of arr) {
console.log(item);
}
Короче говоря, это работает как for
цикл, поскольку он перебирает все, но вам не нужно объявлять и поддерживать счетчик.
Комментарии:
1. Вопрос о том, хорошо ли
forEach
работает с разреженными массивами, является спорным, многие ожидают получитьundefined
значения вместо пропуска.2. Я бы рассмотрел
for
иfor…of
гораздо более идиоматичный, чем.forEach
3. @Bergi о разреженных массивах, это, вероятно, будет зависеть от того, как вы хотите их обработать. По моему опыту, большую часть времени я хотел бы только то, что в них присутствует, хотя я бы сказал, что это не всегда. Я определенно вижу применение для перебора всего. Однако, похоже, что JavaScript (или, возможно, ECMAScript) занял позицию, согласно которой разреженные массивы должны состоять только из любого из его существующих членов. Итак, «хорошо», возможно, потребуется указать там, но для некоторых случаев использования это подходит.
4. @Bergi и about
for
, это везде идиоматично (вероятно, следовало бы сформулировать это именно так, а не «Хорошо узнаваемо»), но я бы не стал считать это специфичным для JS. Методы массива, такие какforEach
,map
,reduce
,filter
, иfind
, являются более отличными от JavaScript. Конечно, они существуют вне ит, но когда речь идет о механизмах обработки массивов JS, они заслуживают своего места, что делает их выделяющимися и хорошо узнаваемыми.
Ответ №3:
влаз уже ответил в комментариях, я бы просто:
Основное отличие заключается в том, что forEach
вызов может генерировать одно замыкание по элементу в массиве, что очень полезно, когда вам нужно повторно использовать некоторые внутренние переменные.