For-each по массиву в JavaScript

avatar
Dante1986
17 февраля 2012 в 13:51
4655917
42
5166

Как я могу перебрать все записи в массиве с помощью JavaScript?

Я думал, что это примерно так:

forEach(instance in theArray)

Где theArray - мой массив, но это кажется неверным.

Источник

Ответы (42)

avatar
T.J. Crowder
17 февраля 2012 в 13:53
7663

TL; DR

  • Ваши лучшие ставки обычно

    • цикл for-of (только ES2015 +; spec | MDN) - простой и удобный для async
      for (const element of theArray) {
          // ...use `element`...
      }
      
    • forEach (только ES5 +; spec | MDN) (или его родственники some и т. П.) - не <706022212229090> -детали <7060222122290128> но7060222122290128 )
      theArray.forEach(element => {
          // ...use `element`...
      });
      
    • простой старомодный цикл for - async - удобный
      for (let index = 0; index < theArray.length; ++index) {
          const element = theArray[index];
          // ...use `element`...
      }
      
    • (редко) for-in с защитой - async - дружественный
      for (const propertyName in theArray) {
          if (/*...is an array element property (see below)...*/) {
              const element = theArray[propertyName];
              // ...use `element`...
          }
      }
      
  • Несколько быстрых ответов:

    • Не используйте for-in , если вы не используете его в качестве мер предосторожности или хотя бы не знаете, почему он может вас укусить.
    • Не используйте map, если вы не используете его возвращаемое значение .
      (К сожалению, есть кто-то, кто преподает map [spec <7060122129117> spec <706012222129117> > MDN], как если бы это было forEach - но, как я пишу в своем блоге, это не то, что он для. Если вы не используете массив, который он создает, не используйте map.)
    • Не используйте forEach , если обратный вызов выполняет асинхронную работу и вы хотите, чтобы forEach ждал, пока эта работа не будет выполнена (потому что этого не произойдет).

Но есть лоты для изучения, читайте дальше ...


JavaScript имеет мощную семантику для циклического перебора массивов и объектов, подобных массиву. Я разделил ответ на две части: параметры для настоящих массивов и параметры для вещей, которые представляют собой просто массив- , например , например объект arguments, другие повторяемые объекты (ES2015 +), коллекции DOM, и т. д.

Хорошо, давайте посмотрим на наши варианты:

Для фактических массивов

У вас есть пять вариантов (два поддерживаются практически навсегда, еще один добавлен в ECMAScript 5 ["ES5"], и еще два добавлены в ECMAScript 2015 ("ES2015", он же "ES6"):

  1. Использовать for-of (использовать итератор неявно) (ES2015 +)
  2. Используйте forEach и аналогичные (ES5 +)
  3. Используйте простой for цикл
  4. Используйте for-in правильно
  5. Явное использование итератора (ES2015 +)

(Вы можете увидеть эти старые спецификации здесь: ES5, ES2015, но оба они были заменены; текущий черновик редактора всегда <12> здесь <70622>.

>

Подробности:

1. Использовать for-of (использовать итератор неявно) (ES2015 +)

ES2015 добавил в JavaScript итераторы и итерации . Массивы итерируемы (как и строки, Map и Set, а также коллекции и списки DOM, как вы увидите позже). Итерируемые объекты предоставляют итераторы для своих значений. Новый оператор for-of перебирает значения, возвращаемые итератором:

const a = ["a", "b", "c"];
for (const element of a) { // You can use `let` instead of `const` if you like
    console.log(element);
}
// a
// b
// c

Нет ничего проще! Под покровом, который получает итератор из массива и перебирает значения, возвращаемые итератором. Итератор, предоставляемый массивами, предоставляет значения элементов массива в порядке от начала до конца.

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

Теоретически цикл for-of включает несколько вызовов функций (один для получения итератора, затем один для получения каждого значения из него). Даже если это правда, беспокоиться не о чем, вызовы функций очень дешевы в современных движках JavaScript (меня беспокоило forEach [ниже], пока я не изучил его; подробности). Но, кроме того, движки JavaScript оптимизируют эти вызовы (в критически важном для производительности коде) при работе с собственными итераторами для таких вещей, как массивы.

for-of полностью async -дружелюбный. Если вам нужно, чтобы работа в теле цикла выполнялась последовательно (а не параллельно), await в теле цикла будет ждать выполнения обещания, прежде чем продолжить. Вот глупый пример:

function delay(ms) {
    return new Promise(resolve => {
        setTimeout(resolve, ms);
    });
}

async function showSlowly(messages) {
    for (const message of messages) {
        await delay(400);
        console.log(message);
    }
}

showSlowly([
    "So", "long", "and", "thanks", "for", "all", "the", "fish!"
]);
// `.catch` omitted because we know it never rejects

Обратите внимание на то, как слова появляются с задержкой перед каждым словом.

Это вопрос стиля кодирования, но for-of - это первое, чего я достигаю при циклическом прохождении чего-либо итеративного.

2. Используйте forEach и аналогичные

В любой даже неопределенно современной среде (то есть в IE8), где у вас есть доступ к Array функциям, добавленным ES5, вы можете использовать forEach (spec | MDN), если вы имеете дело только с синхронным кодом (или вам не нужно ждать завершения асинхронного процесса во время цикла):

const a = ["a", "b", "c"];
a.forEach((element) => {
    console.log(element);
});

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

Подобно for-of, forEach имеет то преимущество, что вам не нужно объявлять переменные индексации и значения в содержащей их области; в этом случае они передаются в качестве аргументов функции итерации и поэтому хорошо ограничены только этой итерацией.

В отличие от for-of, forEach имеет недостаток, заключающийся в том, что он не понимает функции async и await. Если вы используете функцию async в качестве обратного вызова, forEach не ожидает выполнения обещания этой функции, прежде чем продолжить. Вот пример async из for-of с использованием вместо него forEach - обратите внимание, как есть начальная задержка, но затем весь текст появляется сразу, а не ждет:

function delay(ms) {
    return new Promise(resolve => {
        setTimeout(resolve, ms);
    });
}

async function showSlowly(messages) {
    // INCORRECT, doesn't wait before continuing,
    // doesn't handle promise rejections
    messages.forEach(async message => {
        await delay(400);
        console.log(message);
    });
}

showSlowly([
    "So", "long", "and", "thanks", "for", "all", "the", "fish!"
]);
// `.catch` omitted because we know it never rejects

forEach - это функция «перебрать их все», но в ES5 определено несколько других полезных функций «работать через массив и делать что-то», в том числе:

  • every (spec | MDN) - останавливает цикл, когда обратный вызов в первый раз возвращает ложное значение
  • some (spec | MDN) - останавливает цикл при первом возвращении обратным вызовом истинного значения
  • filter (spec | MDN) - создает новый массив, включающий элементы, в которых обратный вызов возвращает истинное значение, исключая те, где его нет
  • map (spec | MDN) - создает новый массив из значений, возвращаемых обратным вызовом
  • reduce (spec | MDN) - наращивает значение, многократно вызывая обратный вызов, передавая предыдущие значения; подробности см. в спецификации
  • reduceRight (spec | MDN) - аналогично reduce, но работает не по возрастанию, а по убыванию

Как и в случае с forEach, если вы используете функцию async в качестве обратного вызова, никто из них не ждет выполнения обещания функции. Это означает:

3. Используйте простой цикл for

Иногда старые способы лучше:

const a = ["a", "b", "c"];
for (let index = 0; index < a.length; ++index) {
    const element = a[index];
    console.log(element);
}

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

const a = ["a", "b", "c"];
for (let index = 0, len = a.length; index < len; ++index) {
    const element = a[index];
    console.log(element);
}

И / или обратный отсчет:

const a = ["a", "b", "c"];
for (let index = a.length - 1; index >= 0; --index) {
    const element = a[index];
    console.log(element);
}

Но с современными движками JavaScript редко нужно выпивать последний кусок сока.

До ES2015 переменная цикла должна была существовать в содержащей области, потому что var имеет только область видимости на уровне функции, а не на уровне блока. Но, как вы видели в приведенных выше примерах, вы можете использовать let внутри for, чтобы ограничить переменные только циклом. И когда вы это сделаете, переменная index воссоздается для каждой итерации цикла, то есть замыкания, созданные в теле цикла, сохраняют ссылку на index для этой конкретной итерации, что решает старую проблему «замыканий в циклах»:

// (The `NodeList` from `querySelectorAll` is array-like)
const divs = document.querySelectorAll("div");
for (let index = 0; index < divs.length; ++index) {
    divs[index].addEventListener('click', e => {
        console.log("Index is: " + index);
    });
}
<div>zero</div>
<div>one</div>
<div>two</div>
<div>three</div>
<div>four</div>

В приведенном выше примере вы получите «Индекс: 0», если щелкнете по первому, и «Индекс: 4», если щелкнете по последнему. Это делает не , если вы используете var вместо let (вы всегда увидите «Индекс: 5»).

Подобно for-of, for циклы хорошо работают в функциях async. Вот предыдущий пример с использованием цикла for:

function delay(ms) {
    return new Promise(resolve => {
        setTimeout(resolve, ms);
    });
}

async function showSlowly(messages) {
    for (let i = 0; i < messages.length; ++i) {
        const message = messages[i];
        await delay(400);
        console.log(message);
    }
}

showSlowly([
    "So", "long", "and", "thanks", "for", "all", "the", "fish!"
]);
// `.catch` omitted because we know it never rejects

4. Используйте for-in правильно

for-in не для перебора массивов, а для перебора имен свойств объекта. Кажется, что он часто работает для циклического перебора массивов как побочного продукта того факта, что массивы являются объектами, но он не просто перебирает индексы массива, он перебирает все перечислимые свойства объекта. (в том числе по наследству). (Раньше также было, что порядок не был указан; теперь это [подробности в этом другом ответе], но даже несмотря на то, что порядок указан сейчас, правила сложны, есть исключения, и полагаться на порядок не лучшая практика.)

Единственные реальные варианты использования for-in в массиве:

  • Это разреженный массив с массивными пробелами в нем, или
  • Вы используете неэлементные свойства объекта массива и хотите включить их в цикл

Рассмотрим только этот первый пример: вы можете использовать for-in для посещения этих разреженных элементов массива, если вы используете соответствующие меры безопасности:

// `a` is a sparse array
const a = [];
a[0] = "a";
a[10] = "b";
a[10000] = "c";
for (const name in a) {
    if (Object.hasOwn(a, name) &&       // These checks are
        /^0$|^[1-9]\d*$/.test(name) &&  // explained
        name <= 4294967294              // below
       ) {
        const element = a[name];
        console.log(a[name]);
    }
}

Обратите внимание на три проверки:

  1. Что объект имеет собственное свойство с этим именем (не то, которое оно наследует от своего прототипа; эта проверка также часто записывается как a.hasOwnProperty(name), но ES2022 добавляет for-in <907060> что может быть более надежным) и

  2. Имя состоит только из десятичных цифр (например, в обычной строковой форме, а не в экспоненциальном представлении), и

  3. Значение имени при приведении к числу <= 2 ^ 32-2 (что составляет 4 294 967 294). Откуда это число? Это часть определения индекса массива в спецификации. Другие числа (нецелые числа, отрицательные числа, числа больше 2 ^ 32-2) не являются индексами массива. Причина, по которой это 2 ^ 32 - 2 , заключается в том, что наибольшее значение индекса меньше 2 ^ 32 - 1 , которое является максимальным значением, которое может иметь length массива. (Например, длина массива соответствует 32-битному целому числу без знака.)

... хотя с учетом сказанного, большая часть кода выполняет только проверку hasOwnProperty.

Вы, конечно, не сделаете этого во встроенном коде. Вы бы написали служебную функцию. Возможно:

// Utility function for antiquated environments without `forEach`
const hasOwn = Object.prototype.hasOwnProperty.call.bind(Object.prototype.hasOwnProperty);
const rexNum = /^0$|^[1-9]\d*$/;
function sparseEach(array, callback, thisArg) {
    for (const name in array) {
        const index = +name;
        if (hasOwn(a, name) &&
            rexNum.test(name) &&
            index <= 4294967294
           ) {
            callback.call(thisArg, array[name], index, array);
        }
    }
}

const a = [];
a[5] = "five";
a[10] = "ten";
a[100000] = "one hundred thousand";
a.b = "bee";

sparseEach(a, (value, index) => {
    console.log("Value at " + index + " is " + value);
});

Как и for, for-in хорошо работает в асинхронных функциях, если работа в нем должна выполняться последовательно.

function delay(ms) {
    return new Promise(resolve => {
        setTimeout(resolve, ms);
    });
}

async function showSlowly(messages) {
    for (const name in messages) {
        if (messages.hasOwnProperty(name)) { // Almost always this is the only check people do
            const message = messages[name];
            await delay(400);
            console.log(message);
        }
    }
}

showSlowly([
    "So", "long", "and", "thanks", "for", "all", "the", "fish!"
]);
// `.catch` omitted because we know it never rejects

5. Явное использование итератора (ES2015 +)

for-of неявно использует итератор, выполняя всю работу за вас. Иногда вам может потребоваться явно использовать итератор . Это выглядит так:

const a = ["a", "b", "c"];
const it = a.values(); // Or `const it = a[Symbol.iterator]();` if you like
let entry;
while (!(entry = it.next()).done) {
    const element = entry.value;
    console.log(element);
}

Итератор - это объект, соответствующий определению итератора в спецификации. Его метод next возвращает новый объект результата каждый раз, когда вы его вызываете. Объект результата имеет свойство done, сообщающее нам, выполнено ли это, и свойство value со значением для этой итерации. (done необязательно, если он будет false, value необязательно, если он будет undefined.)

То, что вы получите для value, зависит от итератора. В массивах итератор по умолчанию предоставляет значение каждого элемента массива ("a", "b" и "c" в предыдущем примере). У массивов также есть три других метода, возвращающих итераторы:

  • values(): это псевдоним для метода [Symbol.iterator], который возвращает итератор по умолчанию.
  • keys(): возвращает итератор, который предоставляет каждый ключ (индекс) в массиве. В приведенном выше примере это будет "0", затем "1", затем "2" (да, в виде строк).
  • entries(): возвращает итератор, который предоставляет массивы [key, value].

Поскольку объекты-итераторы не продвигаются вперед, пока вы не вызовете next, они хорошо работают в циклах функций async. Вот предыдущий пример for-of с явным использованием итератора:

function delay(ms) {
    return new Promise(resolve => {
        setTimeout(resolve, ms);
    });
}

async function showSlowly(messages) {
    const it = messages.values()
    while (!(entry = it.next()).done) {
        await delay(400);
        const element = entry.value;
        console.log(element);
    }
}

showSlowly([
    "So", "long", "and", "thanks", "for", "all", "the", "fish!"
]);
// `.catch` omitted because we know it never rejects

Для объектов, подобных массиву

Помимо истинных массивов, существуют также объекты, похожие на массивы , которые имеют свойство length, и свойства с именами из всех цифр: NodeList экземпляры <

66270947094 HTMLCollection экземпляры, объект arguments и т. Д. Как просмотреть их содержимое в цикле?

Используйте большинство опций выше

По крайней мере, некоторые, а возможно, большая часть или даже все из вышеперечисленных подходов к массивам одинаково хорошо применимы к объектам, подобным массивам:

  1. Использовать for-of (использовать итератор неявно) (ES2015 +)

    for-of использует итератор , предоставленный объектом (если есть). Сюда входят объекты, предоставляемые хостом (например, коллекции и списки DOM). Например, экземпляры HTMLCollection из методов getElementsByXYZ и экземпляры NodeList из querySelectorAll поддерживают итерацию. (Это определено довольно тонко спецификациями HTML и DOM. По сути, любой объект с length и индексированным доступом является автоматически повторяемым. Он не должен быть помечен iterable; это используется только для коллекций, которые, помимо итерируемости, поддерживают методы forEach, values, keys и entries. NodeList делает; HTMLCollection ​​нет, но оба являются итерируемый.)

    Вот пример цикла по элементам div:

const divs = document.querySelectorAll("div");
for (const div of divs) {
    div.textContent = Math.random();
}
<div>zero</div>
<div>one</div>
<div>two</div>
<div>three</div>
<div>four</div>
  1. Использование forEach и связанных (ES5 +)

    Различные функции на Array.prototype являются «преднамеренно общими» и могут использоваться для объектов, подобных массиву, через Function#call (spec | MDN <22>) или <22> спецификация | MDN). (Если вам приходится иметь дело с IE8 или более ранней версией [ай], см. «Предостережение для объектов, предоставляемых хостом» в конце этого ответа, но это не проблема с неопределенно современными браузерами.)

    Предположим, вы хотите использовать forEach в коллекции childNodes childNodes (которая, будучи HTMLCollection, изначально не имеет forEach). Вы бы сделали это:

    Array.prototype.forEach.call(node.childNodes, (child) => {
        // Do something with `child`
    });
    

    (Обратите внимание, что вы можете просто использовать for-of на node.childNodes.)

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

    // (This is all presumably in a module or some scoping function)
    const forEach = Array.prototype.forEach.call.bind(Array.prototype.forEach);
    
    // Then later...
    forEach(node.childNodes, (child) => {
        // Do something with `child`
    });
    
  2. Используйте простой for цикл

    Возможно, очевидно, что простой цикл for работает для объектов, подобных массиву.

  3. Явное использование итератора (ES2015 +)

    См. № 1.

Вы можете обойтись for-in (с мерами предосторожности), но со всеми этими более подходящими вариантами нет причин пытаться.

Создать настоящий массив

В других случаях вы можете захотеть преобразовать объект, подобный массиву, в настоящий массив. Сделать это на удивление легко:

  1. Используйте Array.from

    Array.from (спецификация) | (MDN) (ES2015 +, но легко полифицируется) создает массив из объекта, подобного массиву, при необходимости сначала передавая записи через функцию сопоставления. Итак:

    const divs = Array.from(document.querySelectorAll("div"));
    

    ... берет NodeList из querySelectorAll и создает из него массив.

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

    // Typical use (with an arrow function):
    const divs = Array.from(document.querySelectorAll(".some-class"), element => element.tagName);
    
    // Traditional function (since `Array.from` can be polyfilled):
    var divs = Array.from(document.querySelectorAll(".some-class"), function(element) {
        return element.tagName;
    });
    
  2. Использовать синтаксис распространения (...)

    Также возможно использовать синтаксис расширения ES2015. Как и for-of, здесь используется итератор , предоставленный объектом (см. №1 в предыдущем разделе):

    const trueArray = [...iterableObject];
    

    Так, например, если мы хотим преобразовать NodeList в настоящий массив, с синтаксисом распространения это становится довольно кратким:

    const divs = [...document.querySelectorAll("div")];
    
  3. Используйте slice метод массивов

    Мы можем использовать метод массивов slice, который, как и другие упомянутые выше методы, является «намеренно универсальным» и поэтому может использоваться с объектами, подобными массивам, например:

    const trueArray = Array.prototype.slice.call(arrayLikeObject);
    

    Так, например, если мы хотим преобразовать NodeList в истинный массив, мы могли бы сделать это:

    const divs = Array.prototype.slice.call(document.querySelectorAll("div"));
    

    (Если вам все еще нужно обрабатывать IE8 [ай], произойдет сбой; IE8 не позволял вам использовать объекты, предоставленные хостом, как this таким образом.)

Предупреждение для объектов, предоставляемых хостом

Если вы используете функции Array.prototype с предоставляемыми хостом объектами, подобными массивам (например, коллекции DOM и тому подобное, предоставляемые браузером, а не движком JavaScript), устаревшие браузеры, такие как IE8, не обязательно обработайте это таким образом, поэтому, если вам нужно их поддерживать, обязательно протестируйте в своих целевых средах. Но это не проблема современных браузеров. (Для сред без браузера, естественно, это будет зависеть от среды.)

Aalexander
9 декабря 2020 в 13:08
0

Что вы имеете в виду под неэлементными свойствами?

T.J. Crowder
9 декабря 2020 в 13:18
3

@Alex - свойства массива, которые не представляют элементы массива. Например: const a = ["a", "b"]; a.example = 42; Этот массив имеет три свойства (кроме тех, которые есть у всех массивов), имена которых - строки "0", "1" и "example". Свойство с именем "example" не является свойством элемента. Два других - это свойства элементов, поскольку они представляют элементы массива.

Peter Kionga-Kamau
14 октября 2021 в 10:29
0

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

T.J. Crowder
14 октября 2021 в 10:36
0

@ PeterKionga-Kamau - JavaScript не имеет ассоциативных массивов. Но в случае индексов, три из «лучших ставок» TL; DR предоставляют их: forEach, простой старомодный цикл for, и for-in с мерами безопасности.

Tim Bogdanov
20 октября 2021 в 21:23
0

что, если внутри цикла for вам нужно получить доступ к первому значению массива ex. entry [i] возвращает ['name', 'tim'], но вы хотите получить доступ к jus имени, чтобы сравнить его с другим массивом?

T.J. Crowder
21 октября 2021 в 06:49
0

@TimBogdanov - Извините, я не уверен, что понимаю вопрос. Вы имеете в виду, что у вас есть массив массивов? (Ваш пример выглядит как один элемент массива из Object.entries, который предоставляет массив массивов.) Если это так, везде, где вы видите element выше, вы должны использовать element[1], чтобы получить значение из второго элемента в внутренний массив. (Или вы можете использовать деструктуризацию, , например,.) Но я могу неправильно понять вопрос. :-)

Tim Bogdanov
21 октября 2021 в 15:56
0

@ T.J. Crowder Я поставил это как новый вопрос и получил ответ. coderhelper.com/questions/69653290/…

avatar
Enripro
7 января 2022 в 09:06
-1

Если вы не против очистить массив:

var x;

while(x = y.pop()){ 

    alert(x); //do something 

}
avatar
Enripro
6 января 2022 в 12:34
0

Попробуйте:

var data = [1, 2, 3, 4, 5, 6, 7];

var newData = $.map(data, function(element) {
    if (element % 2 == 0) {
        return element;
    }
});

// newData = [2, 4, 6];
avatar
Felipe Chernicharo
30 августа 2021 в 19:15
11

для ... из | forEach | карта

Использование современного синтаксиса JavaScript для перебора массивов

const fruits = ['????', '????', '????' ]

???????? для ... из

for (const fruit of fruits) {
    console.log(fruit)  // '????', '????', '????'
}

???????? forEach

fruits.forEach(fruit => { 
    console.log(fruit)  // '????', '????', '????'
})

???????? карта

fruits.map(fruit => fruit)   // ['????', '????', '????' ]

???? ВАЖНО: Обычно вы хотите, чтобы ваша map () что-то возвращала, это делает ее идеальной для преобразования массивов.

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

???????? СОВЕТ: вы также можете иметь индекс (а также весь массив) на каждой итерации в ваших функциях .map () или .forEach (). Просто передайте им дополнительные аргументы:

fruits.map((fruit, i) =>  i + '  ' + fruit)

// ['0 ????', '1 ????', '2 ????' ]



fruits.forEach((f, i, arr) => {
    console.log( f + ' ' + i + ' ' +  arr )
})

// ????  0  ????, ????, ????,
// ????  1  ????, ????, ????,
// ????  2  ????, ????, ????,
avatar
Muhammad Waqas
28 марта 2020 в 22:53
3

Предположим, у нас есть массив субъектов:

  let ddl = new Array();
    if (subjects) {
      subjects.forEach(function (s) {ddl.push({"id": s.id,"label": s.name});});
    }
avatar
mojtaba ramezani
27 января 2020 в 06:53
-5

Использование функции grep в jQuery, например:

$.grep([0, 1, 2], function(n, i) {
    return n > 0;
});
avatar
ankitkanojia
22 января 2020 в 08:14
7

В соответствии с новой обновленной функцией ECMAScript 6 (ES6) и ECMAScript 2015, вы можете использовать следующие параметры с циклами:

для циклов

for(var i = 0; i < 5; i++){
  console.log(i);
}

// Output: 0,1,2,3,4

для ... в циклах

let obj = {"a":1, "b":2}

for(let k in obj){
  console.log(k)
}

// Output: a,b

Array.forEach ()

let array = [1,2,3,4]

array.forEach((x) => {
  console.log(x);
})

// Output: 1,2,3,4

для ... циклов

let array = [1,2,3,4]

for(let x of array){
  console.log(x);
}

// Output: 1,2,3,4

циклы while

let x = 0

while(x < 5){
  console.log(x)
  x++
}

// Output: 1,2,3,4

do ... while циклы

let x = 0

do{
  console.log(x)
  x++
}while(x < 5)

// Output: 1,2,3,4
avatar
vkarpov15
23 декабря 2019 в 19:31
3

Я бы сказал, что for/of - лучший вариант:

const arr = ['a', 'b', 'c'];

for (const v of arr) {
  console.log(v); // Prints "a", "b", "c"
}
  • В отличие от for/in, for/of пропускает нечисловые свойства в массиве. Например, если вы установите arr.foo = 'test', for (var v in arr) будет проходить через клавишу 'foo'.

  • В отличие от forEach(), for/of не пропускает «дыры» в массивах. const arr = ['a', 'c'] - допустимый JavaScript, только второй элемент - это «дыра». Массив функционально эквивалентен ['a', undefined, 'c'].

Подробнее см. в этом сообщении блога о for/of и forEach().

avatar
Mustafa Kunwa
19 декабря 2019 в 12:26
5

Вы можете использовать:

  1. ForEach

    theArray.forEach(function (array, index) {
        console.log(index);
        console.log(array);
    });
    
  2. для

    for(var i=0; i<theArray.length; i++) {
        console.log(i)
    }
    
  3. карта

    theArray.map(x => console.log(x));
    
  4. карта

    theArray.filter(x => console.log(x));
    

И есть много других для повторения.

avatar
Kamil Kiełczewski
18 декабря 2019 в 17:09
9

Производительность

Сегодня (2019-12-18) я провожу тест на своей macOS v10.13.6 (High Sierra), на Chrome v 79.0, Safari v13.0.4 и Firefox v71.0 (64 бит) - выводы об оптимизации (и микрооптимизация , которую обычно не стоит вводить в код, потому что выгода небольшая, но сложность кода растет).

  • Похоже, традиционный for i ( Aa ) - хороший выбор для написания быстрого кода во всех браузерах.

  • Другие решения, такие как for-of ( Ad ), все в группе C. ... обычно в 2-10 (и более) раз медленнее, чем Aa , но для небольших массивов его можно использовать - для повышения ясности кода.

  • Циклы с длиной массива, кэшированной в n ( Ab, Bb, Be ), иногда быстрее, иногда нет. Вероятно, компиляторы автоматически обнаруживают эту ситуацию и вводят кеширование. Разница в скорости между кэшированной и не кэшированной версиями ( Aa, Ba, Bd ) составляет около ~ 1%, поэтому похоже, что введение n - это микрооптимизация .

  • Решения, подобные i--, где цикл начинается с последнего элемента массива ( Ac, Bc ), обычно примерно на 30% медленнее, чем решения прямого распространения - вероятно, причина в способе Кэш памяти ЦП работает - прямое чтение памяти более оптимально для кэширования ЦП). НЕ РЕКОМЕНДУЕТСЯ ИСПОЛЬЗОВАТЬ такие решения.

Подробности

В тестах мы вычисляем сумму элементов массива. Я провожу тест для небольших массивов (10 элементов) и больших массивов (1M элементов) и делю их на три группы:

  • A - for тесты
  • B - while тесты
  • C - другие / альтернативные методы

let arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
//let arr = Array.from(Array(1000000), (x, i) => i%10);

function Aa(a, s=0) {
  for(let i=0; i<a.length; i++) {
    s += a[i];
  }
  console.log('Aa=', s);
}

function Ab(a, s=0) {
  let n = a.length;
  for(let i=0; i<n; i++) {
    s += a[i];
  }
  console.log('Ab=', s);
}

function Ac(a, s=0) {
  for(let i=a.length; i--;) {
    s += a[i];
  }
  console.log('Ac=', s);
}

function Ad(a, s=0) {
  for(let x of a) {
    s += x;
  }
  console.log('Ad=', s);
}

function Ae(a, s=0) {
  for(let i in a) if (a.hasOwnProperty(i)) {
    s += a[i];
  }
  console.log('Ae=', s);
}

function Ba(a, s=0) {
  let i = -1;
  while(++i < a.length) {
    s+= a[i];
  }
  console.log('Ba=', s);
}

function Bb(a, s=0) {
  let i = -1;
  let n = a.length;
  while(++i < n) {
    s+= a[i];
  }
  console.log('Bb=', s);
}

function Bc(a, s=0) {
  let i = a.length;
  while(i--) {
    s += a[i];
  }
  console.log('Bc=', s);
}

function Bd(a, s=0) {
  let i = 0;
  do {
    s+= a[i]
  } while (++i < a.length);
  console.log('Bd=', s);
}

function Be(a, s=0) {
  let i = 0;
  let n = a.length;
  do {
    s += a[i]
  } while (++i < n);
  console.log('Be=', s);
}

function Bf(a, s=0) {
  const it = a.values(); 
  let e;
  while (!(e = it.next()).done) { 
    s+= e.value; 
  }
  console.log('Bf=', s);
}

function Ca(a, s=0) {
  a.map(x => { s+=x });
  console.log('Ca=', s);
}

function Cb(a, s=0) {
  a.forEach(x => { s+=x });
  console.log('Cb=', s);
}

function Cc(a, s=0) {
  a.every(x => (s += x, 1));
  console.log('Cc=', s);
}

function Cd(a, s=0) {
  a.filter(x => { s+=x });
  console.log('Cd=',s);
}

function Ce(a, s=0) {
  a.reduce((z, c) => { s+=c }, 0);
  console.log('Ce=', s);
}

function Cf(a, s=0) {
  a.reduceRight((z, c) => { s += c }, 0);
  console.log('Cf=', s);
}

function Cg(a, s=0) {
  a.some(x => { s += x } );
  console.log('Cg=', s);
}

function Ch(a, s=0) {
  Array.from(a, x=> s += x);
  console.log('Cc=', s);
}


Aa(arr);
Ab(arr);
Ac(arr);
Ad(arr);
Ae(arr);

Ba(arr);
Bb(arr);
Bc(arr);
Bd(arr);
Be(arr);
Bf(arr);

Ca(arr);
Cb(arr);
Cc(arr);
Cd(arr);
Ce(arr);
Cf(arr);
Cg(arr);
Ch(arr);
<p style="color: red">This snippets only PRESENTS code used for benchmark - it not perform test itself</p>

Результаты кроссбраузерности

Результаты для всех протестированных браузеров

Enter image description here браузеры **

Массив из 10 элементов

Результаты для Chrome. Вы можете выполнить тест на своем компьютере здесь.

Enter image description here

Массив с 1 000 000 элементов

Результаты для Chrome. Вы можете выполнить тест на своем компьютере здесь

Enter image description here

avatar
antelove
14 декабря 2019 в 10:24
0

Документация Mozilla

/* Get all forms */
document.querySelectorAll( "form" ).forEach( form => {

  /* For each form, add the onsubmit event */
  form.addEventListener( "submit", event => {
    event.preventDefault(); // Return false

    /* Display it */
    alert(event.target.action);
    console.log(event.target);
  } );

} );
<form action="form1.php" >
  <input type="submit" value="Submit" />
</form>
<form action="form2.php" >
  <input type="submit" value="Submit" />
</form>
<form action="form3.php" >
  <input type="submit" value="Submit" />
</form>
avatar
subhashish negi
8 марта 2019 в 14:04
6

Если вы хотите перебрать массив объектов с помощью функции стрелки:

let arr = [{name:'john', age:50}, {name:'clark', age:19}, {name:'mohan', age:26}];

arr.forEach((person)=>{
  console.log('I am ' + person.name + ' and I am ' + person.age + ' old');
})
avatar
alejoko
2 февраля 2019 в 15:13
2

Если вы хотите сохранить свой код в рабочем состоянии, используйте map:

theArray.map(instance => do_something);

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

avatar
arul prince
21 января 2019 в 13:08
3

// Looping through arrays using the foreach ECMAScript 6 way

var data = new Array(1, 2, 3, 4, 5);
data.forEach((val,index) => {
    console.log("index: ", index); // Index
    console.log("value: ", val); // Value
});
avatar
Peko Chan
12 декабря 2018 в 11:06
0

Я пришел из Python, и этот способ мне показался более понятным.

theArray - это массив, а instance - элементы массива:

for (let instance of theArray)
{
    console.log("The instance", instance);
}

или

for (instance in theArray)
{
    console.log("The instance", instance);
}

сравнить с:

theArray.forEach(function(instance) {
    console.log(instance);
});

Но, в конце концов, оба делают одно и то же.

avatar
darklightcode
9 октября 2018 в 20:19
10

Использование циклов с ECMAScript 6 деструктуризацией и оператором распространения

Деструктуризация и использование оператора распространения оказались весьма полезными для новичков в ECMAScript 6, поскольку они более удобочитаемы / эстетичны, хотя некоторые ветераны JavaScript могут посчитать это беспорядочным. Это может пригодиться юниорам или другим людям.

В следующих примерах будет использоваться оператор for...of и метод .forEach.

Примеры 6, 7 и 8 могут использоваться с любыми функциональными циклами, такими как .map, .filter, .reduce, .sort, .every, <246865>. Дополнительные сведения об этих методах см. В объекте массива.

Пример 1: Обычный for...of цикл - никаких фокусов.

let arrSimple = ['a', 'b', 'c'];

for (let letter of arrSimple) {
  console.log(letter);
}

Пример 2: Разделить слова на символы

let arrFruits = ['apple', 'orange', 'banana'];

for (let [firstLetter, ...restOfTheWord] of arrFruits) {
  // Create a shallow copy using the spread operator
  let [lastLetter] = [...restOfTheWord].reverse();
  console.log(firstLetter, lastLetter, restOfTheWord);
}

Пример 3: Цикл с key и value

// let arrSimple = ['a', 'b', 'c'];

// Instead of keeping an index in `i` as per example `for(let i = 0 ; i<arrSimple.length;i++)`
// this example will use a multi-dimensional array of the following format type:
// `arrWithIndex: [number, string][]`

let arrWithIndex = [
  [0, 'a'],
  [1, 'b'],
  [2, 'c'],
];

// Same thing can be achieved using `.map` method
// let arrWithIndex = arrSimple.map((i, idx) => [idx, i]);

// Same thing can be achieved using `Object.entries`
// NOTE: `Object.entries` method doesn't work on Internet Explorer  unless it's polyfilled
// let arrWithIndex = Object.entries(arrSimple);

for (let [key, value] of arrWithIndex) {
  console.log(key, value);
}

Пример 4: Получить свойства объекта в строке

let arrWithObjects = [{
    name: 'Jon',
    age: 32
  },
  {
    name: 'Elise',
    age: 33
  }
];

for (let { name, age: aliasForAge } of arrWithObjects) {
  console.log(name, aliasForAge);
}

Пример 5: Получите глубокие свойства объекта того, что вам нужно

let arrWithObjectsWithArr = [{
    name: 'Jon',
    age: 32,
    tags: ['driver', 'chef', 'jogger']
  },
  {
    name: 'Elise',
    age: 33,
    tags: ['best chef', 'singer', 'dancer']
  }
];

for (let { name, tags: [firstItemFromTags, ...restOfTags] } of arrWithObjectsWithArr) {
  console.log(name, firstItemFromTags, restOfTags);
}

Пример 6: Используется ли Пример 3 с .forEach

let arrWithIndex = [
  [0, 'a'],
  [1, 'b'],
  [2, 'c'],
];

// Not to be confused here, `forEachIndex` is the real index
// `mappedIndex` was created by "another user", so you can't really trust it

arrWithIndex.forEach(([mappedIndex, item], forEachIndex) => {
  console.log(forEachIndex, mappedIndex, item);
});

Пример 7: Используется Пример 4 с .forEach

let arrWithObjects = [{
    name: 'Jon',
    age: 32
  },
  {
    name: 'Elise',
    age: 33
  }
];
// NOTE: Destructuring objects while using shorthand functions
// are required to be surrounded by parentheses
arrWithObjects.forEach( ({ name, age: aliasForAge }) => {
  console.log(name, aliasForAge)
});

Пример 8: Используется Пример 5 с .forEach

let arrWithObjectsWithArr = [{
    name: 'Jon',
    age: 32,
    tags: ['driver', 'chef', 'jogger']
  },
  {
    name: 'Elise',
    age: 33,
    tags: ['best chef', 'singer', 'dancer']
  }
];

arrWithObjectsWithArr.forEach(({
  name,
  tags: [firstItemFromTags, ...restOfTags]
}) => {
  console.log(name, firstItemFromTags, restOfTags);
});
avatar
Willem van der Veen
8 сентября 2018 в 07:55
7

Сводка:

При итерации по массиву мы часто хотим достичь одной из следующих целей:

  1. Мы хотим перебрать массив и создать новый массив:

    Array.prototype.map

  2. Мы хотим перебрать массив и не создавать новый массив:

    Array.prototype.forEach

    for..of петля

В JavaScript есть много способов достижения обеих этих целей. Однако одни удобнее других. Ниже вы можете найти некоторые часто используемые методы (наиболее удобный IMO) для выполнения итерации массива в JavaScript.

Создание нового массива: Map

map() - это функция, расположенная на Array.prototype, которая может преобразовывать каждый элемент массива, а затем возвращает новый массив . map() принимает в качестве аргумента функцию обратного вызова и работает следующим образом:

let arr = [1, 2, 3, 4, 5];

let newArr = arr.map((element, index, array) => {
  return element * 2;
})

console.log(arr);
console.log(newArr);

Обратный вызов, который мы передали в map() в качестве аргумента, выполняется для каждого элемента. Затем возвращается массив, имеющий ту же длину, что и исходный массив. В этом новом элементе массива функция обратного вызова передается в качестве аргумента в map().

Четкое различие между map и другим механизмом цикла, например forEach и циклом for..of, заключается в том, что map возвращает новый массив и оставляет старый массив нетронутым , кроме случаев, когда вы явно манипулируйте им с помощью мыслей типа splice).

Также обратите внимание, что обратный вызов функции map предоставляет номер индекса текущей итерации в качестве второго аргумента. Кроме того, предоставляет ли третий аргумент массив, для которого был вызван map? Иногда эти свойства могут быть очень полезными.

Цикл с использованием forEach

forEach - это функция, которая находится на Array.prototype и принимает в качестве аргумента функцию обратного вызова. Затем он выполняет эту функцию обратного вызова для каждого элемента в массиве. В отличие от функции map(), функция forEach ничего не возвращает (undefined). Например:

let arr = [1, 2, 3, 4, 5];

arr.forEach((element, index, array) => {

  console.log(element * 2);

  if (index === 4) {
    console.log(array)
  }
  // index, and oldArray are provided as 2nd and 3th argument by the callback

})

console.log(arr);

Как и функция map, обратный вызов forEach предоставляет порядковый номер текущей итерации в качестве второго аргумента. Кроме того, предоставляет ли третий аргумент массив, для которого был вызван forEach?

Перебирать элементы с помощью for..of

Цикл for..of проходит через каждый элемент массива (или любого другого итеративного объекта). Это работает следующим образом:

let arr = [1, 2, 3, 4, 5];

for(let element of arr) {
  console.log(element * 2);
}

В приведенном выше примере element обозначает элемент массива, а arr - массив, который мы хотим выполнить в цикле. Обратите внимание, что имя element произвольно, и мы могли бы выбрать любое другое имя, например «el» или что-то более декларативное, когда это применимо.

Не путайте цикл for..in с циклом for..of. for..in будет перебирать все перечисляемые свойства массива, тогда как цикл for..of будет перебирать только элементы массива. Например:

let arr = [1, 2, 3, 4, 5];

arr.foo = 'foo';

for(let element of arr) {
  console.log(element);
}

for(let element in arr) {
  console.log(element);
}
avatar
Nouman Dilshad
17 июля 2018 в 12:30
7

Вы можете позвонить каждому так:

forEach будет перебирать предоставленный вами массив, и для каждой итерации он будет иметь element, который содержит значение этой итерации. Если вам нужен индекс, вы можете получить текущий индекс, передав i в качестве второго параметра в функции обратного вызова forEach.

Foreach - это, по сути, функция высшего порядка, которая принимает другую функцию в качестве параметра.

let theArray= [1,3,2];

theArray.forEach((element) => {
  // Use the element of the array
  console.log(element)
}

Вывод:

1
3
2

Вы также можете перебирать массив следующим образом:

for (let i=0; i<theArray.length; i++) {
  console.log(i); // i will have the value of each index
}
avatar
BlackBeard
6 июля 2018 в 07:11
5

Если у вас массивный массив, вы должны использовать iterators для повышения эффективности. Итераторы являются свойством некоторых коллекций JavaScript (например, Map, Set, <8688109608608608608608608606910608608608608608608608608608608608608608608608608608608608 / 8688109608608608608608 . Даже for..of использует iterator под капюшоном. <868810960

Итераторы повышают эффективность, позволяя потреблять элементы в списке по одному, как если бы они были потоком. Что делает итератор особенным, так это то, как он проходит по коллекции. Другие циклы должны загружать всю коллекцию заранее, чтобы перебирать ее, тогда как итератору нужно знать только текущую позицию в коллекции.

Вы получаете доступ к текущему элементу, вызывая метод итератора next. Следующий метод вернет value текущего элемента и boolean , чтобы указать, когда вы достигли конца коллекции. Ниже приведен пример создания итератора из массива.

Преобразуйте обычный массив в итератор, используя метод values() следующим образом:

    const myArr = [2,3,4]

let it = myArr.values();

console.log(it.next());
console.log(it.next());
console.log(it.next());
console.log(it.next());

Вы также можете преобразовать обычный массив в итератор, используя Symbol.iterator следующим образом:

const myArr = [2,3,4]

let it = myArr[Symbol.iterator]();

console.log(it.next());
console.log(it.next());
console.log(it.next());
console.log(it.next());

Вы также можете преобразовать обычный array в iterator следующим образом:

let myArr = [8, 10, 12];

function makeIterator(array) {
    var nextIndex = 0;
    
    return {
       next: function() {
           return nextIndex < array.length ?
               {value: array[nextIndex++], done: false} :
               {done: true};
       }
    };
};

var it = makeIterator(myArr);

console.log(it.next().value);   // {value: 8, done: false}
console.log(it.next().value);   // {value: 10, done: false}
console.log(it.next().value);   // {value: 12, done: false}
console.log(it.next().value);   // {value: undefined, done: true}

ПРИМЕЧАНИЕ :

  • Итераторы по своей природе исчерпаемы.
  • По умолчанию объекты не iterable. В этом случае используйте for..in, потому что вместо значений он работает с ключами.

Вы можете узнать больше о iteration protocol здесь.

avatar
Harun Or Rashid
30 мая 2018 в 09:05
6

Если вы хотите использовать forEach(), это будет выглядеть так -

theArray.forEach ( element => {
    console.log(element);
});

Если вы хотите использовать for(), это будет выглядеть так -

for(let idx = 0; idx < theArray.length; idx++){
    let element = theArray[idx];
    console.log(element);
}
avatar
John
11 января 2018 в 18:03
1
var a = ["car", "bus", "truck"]
a.forEach(function(item, index) {
    console.log("Index" + index);
    console.log("Element" + item);
})
avatar
Murtuza Husain
11 ноября 2017 в 06:16
7

Лямбда-синтаксис обычно не работает в Internet Explorer 10 или более ранней версии.

Я обычно использую

[].forEach.call(arrayName,function(value,index){
    console.log("value of the looped element" + value);
    console.log("index of the looped element" + index);
});

Если вы поклонник jQuery и у вас уже запущен файл jQuery, вам следует поменять местами параметры индекса и значения

$("#ul>li").each(function(**index, value**){
    console.log("value of the looped element" + value);
    console.log("index of the looped element" + index);
});
avatar
Ante Jablan Adamović
9 ноября 2017 в 15:31
8

Наиболее близким к вашей идее будет использование Array.forEach(), которое принимает функцию закрытия, которая будет выполняться для каждого элемента массива.

myArray.forEach(
  (item) => {
    // Do something
    console.log(item);
  }
);

Другой жизнеспособный способ - использовать Array.map(), который работает таким же образом, но также принимает все возвращаемые вами значения и возвращает их в новом массиве (по сути, сопоставляя каждый элемент с новым), например:

var myArray = [1, 2, 3];
myArray = myArray.map(
  (item) => {
    return item + 1;
  }
);

console.log(myArray); // [2, 3, 4]
avatar
Alireza
10 мая 2017 в 14:32
24

Существует несколько способов для перебора массива в JavaScript, как показано ниже:

для - это самый распространенный . Полный блок кода для цикла

var languages = ["Java", "JavaScript", "C#", "Python"];
var i, len, text;
for (i = 0, len = languages.length, text = ""; i < len; i++) {
    text += languages[i] + "<br>";
}
document.getElementById("example").innerHTML = text;
<p id="example"></p>

while - цикл, пока условие выполнено. Кажется, самый быстрый шлейф

var text = "";
var i = 0;
while (i < 10) {
    text +=  i + ") something<br>";
    i++;
}
document.getElementById("example").innerHTML = text;
<p id="example"></p>

do / while - также цикл через блок кода, пока условие истинно, будет выполняться хотя бы один раз

var text = ""
var i = 0;

do {
    text += i + ") something <br>";
    i++;
}
while (i < 10);

document.getElementById("example").innerHTML = text;
<p id="example"></p>

Функциональные циклы - forEach, map, filter, а также reduce (они проходят через функцию, но они используются, если вам нужно что-то сделать с вашим массивом и т. Д. .

// For example, in this case we loop through the number and double them up using the map function
var numbers = [65, 44, 12, 4];
document.getElementById("example").innerHTML = numbers.map(function(num){return num * 2});
<p id="example"></p>

Для получения дополнительной информации и примеров функционального программирования на массивах см. Сообщение в блоге Функциональное программирование на JavaScript: отображение, фильтрация и сокращение .

avatar
Anil Kumar Arya
9 апреля 2017 в 16:51
23

ECMAScript 5 (версия на JavaScript) для работы с массивами:

forEach - перебирает каждый элемент в массиве и делает все, что вам нужно, с каждым элементом.

['C', 'D', 'E'].forEach(function(element, index) {
  console.log(element + " is #" + (index+1) + " in the musical scale");
});

// Output
// C is the #1 in musical scale
// D is the #2 in musical scale
// E is the #3 in musical scale

В случае, если вас больше интересует работа с массивом с использованием какой-либо встроенной функции.

map - создает новый массив с результатом функции обратного вызова. Этот метод хорошо использовать, когда вам нужно отформатировать элементы вашего массива.

// Let's upper case the items in the array
['bob', 'joe', 'jen'].map(function(elem) {
  return elem.toUpperCase();
});

// Output: ['BOB', 'JOE', 'JEN']

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

[1,2,3,4].reduce(function(previous, current) {
  return previous + current;
});
// Output: 10
// 1st iteration: previous=1, current=2 => result=3
// 2nd iteration: previous=3, current=3 => result=6
// 3rd iteration: previous=6, current=4 => result=10

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

// Check if everybody has 18 years old of more.
var ages = [30, 43, 18, 5];
ages.every(function(elem) {
  return elem >= 18;
});

// Output: false

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

// Finding the even numbers
[1,2,3,4,5,6].filter(function(elem){
  return (elem % 2 == 0)
});

// Output: [2,4,6]
avatar
Zaz
26 мая 2016 в 16:14
35

Согласно ECMAScript 6:

list = [0, 1, 2, 3]
for (let obj of list) {
    console.log(obj)
}

Где of избегает странностей, связанных с in, и заставляет его работать как цикл for любого другого языка, а let связывает i внутри цикла, а не внутри функции.

Фигурные скобки ({}) можно опустить, когда есть только одна команда (например, в примере выше).

avatar
Volkan Seçkin Akbayır
28 августа 2015 в 07:27
18

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

var foo = [object,object,object];
for (var i = foo.length, item; item = foo[--i];) {
    console.log(item);
}

Плюсы:

Преимущество этого: у вас уже есть ссылка в первой строке, поэтому не нужно будет объявлять ее позже в другой строке. Это удобно при циклическом перемещении по массиву объектов.

Минусы:

Это прерывается всякий раз, когда ссылка ложная - ложная (неопределенная и т. Д.). Однако это можно использовать как преимущество. Однако читать будет немного сложнее. А также, в зависимости от браузера, он может быть «не» оптимизирован для работы быстрее исходного.

avatar
Priyanshu Chauhan
27 июля 2015 в 07:07
20

Нет встроенной возможности взлома в forEach. Чтобы прервать выполнение, используйте Array#some, как показано ниже:

[1,2,3].some(function(number) {
    return number === 1;
});

Это работает, потому что some возвращает истину, как только любой из обратных вызовов, выполняемых в порядке массива, возвращает истину, сокращая выполнение остальных. Исходный ответ см. прототип массива для некоторых

avatar
user2359695
20 июня 2014 в 22:56
39

Я знаю, что это старый пост, и уже есть так много отличных ответов. Для большей полноты я решил добавить еще один, используя AngularJS. Конечно, это применимо только в том случае, если вы используете Angular, очевидно, тем не менее, я все равно хотел бы это сказать.

angular.forEach принимает 2 аргумента и необязательный третий аргумент. Первый аргумент - это объект (массив), по которому выполняется итерация, второй аргумент - это функция итератора, а необязательный третий аргумент - это контекст объекта (в основном упоминаемый внутри цикла как 'this'.

Есть разные способы использования цикла forEach для angular. Самый простой и, вероятно, наиболее используемый -

var temp = [1, 2, 3];
angular.forEach(temp, function(item) {
    //item will be each element in the array
    //do something
});

Другой способ копирования элементов из одного массива в другой -

var temp = [1, 2, 3];
var temp2 = [];
angular.forEach(temp, function(item) {
    this.push(item); //"this" refers to the array passed into the optional third parameter so, in this case, temp2.
}, temp2);

Хотя этого делать не обязательно, вы можете просто сделать следующее, что эквивалентно предыдущему примеру:

angular.forEach(temp, function(item) {
    temp2.push(item);
});

Теперь есть плюсы и минусы использования функции angular.forEach в отличие от встроенного цикла for со вкусом ванили.

Плюсы

  • Удобная читаемость
  • Легкость записи
  • Если доступно, angular.forEach будет использовать цикл ES5 forEach. Теперь я перейду к эффективности в разделе cons, поскольку циклы forEach намного медленнее, чем циклы for. Я упоминаю это как профессионал, потому что хорошо быть последовательным и стандартизированным.

Рассмотрим следующие 2 вложенных цикла, которые делают то же самое. Допустим, у нас есть 2 массива объектов, и каждый объект содержит массив результатов, каждый из которых имеет свойство Value, которое представляет собой строку (или что-то еще). Допустим, нам нужно перебрать каждый из результатов и, если они равны, выполнить какое-то действие:

angular.forEach(obj1.results, function(result1) {
    angular.forEach(obj2.results, function(result2) {
        if (result1.Value === result2.Value) {
            //do something
        }
    });
});

//exact same with a for loop
for (var i = 0; i < obj1.results.length; i++) {
    for (var j = 0; j < obj2.results.length; j++) {
        if (obj1.results[i].Value === obj2.results[j].Value) {
            //do something
        }
    }
}

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

Минусы

  • Эффективность. angular.forEach и исходный forEach, если на то пошло, оба настолько медленнее, чем обычный цикл for .... примерно на 90% медленнее. Поэтому для больших наборов данных лучше всего использовать собственный цикл for.
  • Нет перерыва, продолжения или возврата поддержки. continue на самом деле поддерживается «аварией», чтобы продолжить в angular.forEach, вы просто поместите оператор return; в функцию, например angular.forEach(array, function(item) { if (someConditionIsTrue) return; });, что приведет к ее выходу из функции на эта итерация. Это также связано с тем, что собственный forEach не поддерживает ни прерывание, ни продолжение.

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

avatar
joeytwiddle
2 мая 2014 в 14:21
137

Цикл назад

Я думаю, что обратный цикл for заслуживает упоминания здесь:

for (var i = array.length; i--; ) {
     // process array[i]
}

Преимущества:

  • Вам не нужно объявлять временную переменную len или сравнивать с array.length на каждой итерации, любая из которых может быть минутной оптимизацией.
  • Удаление братьев и сестер из DOM в обратном порядке обычно более эффективно . (Браузеру нужно меньше перемещать элементы во внутренних массивах.)
  • Если вы изменяете массив во время цикла, с индексом i или после него (например, вы удаляете или вставляете элемент в array[i]), то прямой цикл пропустит элемент, который смещен влево в положение i , или повторно обработать i -й элемент, который был смещен вправо. В традиционном цикле for вы могли бы обновить i , чтобы указать на следующий элемент, который требует обработки - 1, но простое изменение направления итерации часто приводит к проще и более элегантное решение.
  • Аналогично, при изменении или удалении вложенных элементов DOM обратная обработка может обойти ошибки . Например, рассмотрите возможность изменения innerHTML родительского узла перед обработкой его дочерних узлов. К тому времени, когда дочерний узел будет достигнут, он будет отсоединен от DOM, будучи заменен вновь созданным дочерним узлом при записи родительского innerHTML.
  • Это короче для ввода и читать , чем некоторые другие доступные варианты. Хотя он проигрывает forEach() и for ... of ES6.

Недостатки:

  • Он обрабатывает элементы в обратном порядке. Если вы строили новый массив из результатов или выводили что-то на экран, естественно результат будет обратным относительно исходного порядка.
  • Неоднократная вставка братьев и сестер в DOM в качестве первого дочернего элемента для сохранения их порядка менее эффективна . (Браузеру все равно придется сдвигать вещи правильно.) Чтобы создавать узлы DOM эффективно и по порядку, просто выполните цикл вперед и добавьте как обычно (а также используйте «фрагмент документа»).
  • Обратный цикл сбивает с толку младших разработчиков. (Вы можете считать это преимуществом, в зависимости от вашего мировоззрения.)

Должен ли я всегда его использовать?

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

Хотя прирост производительности обычно незначительный, он вроде кричит:

«Просто проделайте это с каждым элементом в списке, меня не волнует порядок!»

Однако на практике это не на самом деле надежное указание на намерение, поскольку оно неотличимо от тех случаев, когда вы выполняете и заботитесь о заказе7 действительно нужно для обратного цикла. Так что на самом деле потребуется другая конструкция для точного выражения намерения «безразлично», что в настоящее время недоступно для большинства языков, включая ECMAScript, но которую можно назвать, например, forEachUnordered().

Если порядок не имеет значения, а эффективность вызывает беспокойство (в самом внутреннем цикле игры или движка анимации), тогда может быть приемлемо использовать обратный цикл for в качестве основного шаблон. Просто помните, что наличие обратного цикла for в существующем коде не обязательно означает , что порядок не имеет значения!

Лучше было использовать forEach ()

В целом для кода более высокого уровня, где ясность и безопасность вызывают большее беспокойство, я ранее рекомендовал использовать Array::forEach в качестве шаблона по умолчанию для циклов (хотя в наши дни я предпочитаю использовать for..of). Причины для предпочтения forEach обратному циклу:

  • Понятнее читать.
  • Это указывает на то, что i не будет сдвигаться внутри блока (что всегда может быть неожиданностью, скрывающейся в длинных циклах for и while).
  • Это дает вам свободный простор для закрытия.
  • Это уменьшает утечку локальных переменных и случайное столкновение с внешними переменными (и изменение).

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

(Если обсуждение намерения не имеет для вас смысла, тогда вам и вашему коду может быть полезно посмотреть лекцию Крокфорда на тему Стиль программирования и ваш мозг.)

Теперь его еще лучше использовать для ... of!

Существуют споры о том, что предпочтительнее: for..of или forEach():

  • Для максимальной поддержки браузера for..of требуется полифилл для итераторов, что делает ваше приложение немного медленнее для выполнения и немного больше для загрузки.

  • По этой причине (и для поощрения использования map и filter), некоторые руководства по внешнему интерфейсу полностью запретить for..of81581495>

  • Но вышеуказанные проблемы не применимы к приложениям Node.js, где for..of теперь хорошо поддерживается.

  • И, кроме того, await не работает внутри forEach(). Использование for..of является наиболее четким шаблоном в этом случае.

Лично я предпочитаю использовать то, что кажется наиболее легким для чтения, если только производительность или минимизация не стали серьезной проблемой. Поэтому в наши дни я предпочитаю использовать for..of вместо forEach(), но я всегда буду использовать map или filter или find <

2> или или <86542997958>, если применимо. . (Ради своих коллег я редко использую reduce.)


Как это работает?

for (var i = 0; i < array.length; i++) { ... }   // Forwards

for (var i = array.length; i--; )    { ... }   // Reverse

Вы заметите, что i-- - это среднее предложение (где мы обычно видим сравнение), а последнее предложение пустое (где мы обычно видим i++). Это означает, что i-- также используется как условие для продолжения. Важно отметить, что он выполняется и проверяется перед каждой итерацией.

  • Как это может начаться с array.length без взрыва?

    Поскольку i-- запускается перед на каждой итерации, на первой итерации мы фактически будем получать доступ к элементу по адресу array.length - 1, что позволяет избежать любых проблем с массивом <85642 вне границ -997 > undefined поз.

  • Почему не прекращается итерация до индекса 0?

    Цикл прекращает итерацию, когда условие i-- оценивается как ложное значение (когда оно дает 0).

    Хитрость в том, что, в отличие от --i, конечный оператор i-- уменьшает i, но возвращает значение перед <8654299795. Ваша консоль может продемонстрировать это:

    > var i = 5; [i, i--, i];

    [5, 5, 4]

    Итак, на последней итерации i ранее было 1 , а выражение i-- изменяет его на 0 <8654299799795> 0 <8654299799795> на самом деле > (правда), и так условие проходит. На следующей итерации i-- изменяет i на -1 , но дает 0 (falsey), в результате чего выполнение нижней части цикла немедленно выпадает из цикла.

    В традиционных форвардах для цикла i++ и ++i взаимозаменяемы (как указывает Дуглас Крокфорд). Однако в обратном цикле for, поскольку наш декремент также является выражением нашего условия, мы должны придерживаться i--, если мы хотим обработать элемент с индексом 0.


Общая информация

Некоторым нравится рисовать маленькую стрелку в обратном цикле for и заканчивать подмигиванием:

for (var i = array.length; i --> 0 ;) {

Благодарим WYL за то, что он показал мне преимущества и ужасы обратного цикла for.

avatar
Daniel W.
1 апреля 2014 в 11:15
12

способ jQuery с использованием $.map:

var data = [1, 2, 3, 4, 5, 6, 7];

var newData = $.map(data, function(element) {
    if (element % 2 == 0) {
        return element;
    }
});

// newData = [2, 4, 6];
avatar
Tim
30 января 2014 в 15:25
25

Это итератор для НЕ разреженного списка, где индекс начинается с 0, что является типичным сценарием при работе с document.getElementsByTagName или document.querySelectorAll)

function each( fn, data ) {

    if(typeof fn == 'string')
        eval('fn = function(data, i){' + fn + '}');

    for(var i=0, L=this.length; i < L; i++) 
        fn.call( this[i], data, i );   

    return this;
}

Array.prototype.each = each;  

Примеры использования:

Пример №1

var arr = [];
[1, 2, 3].each( function(a){ a.push( this * this}, arr);
arr = [1, 4, 9]

Пример 2

each.call(document.getElementsByTagName('p'), "this.className = data;",'blue');

Каждый тег p получает class="blue"

Пример №3

each.call(document.getElementsByTagName('p'), 
    "if( i % 2 == 0) this.className = data;",
    'red'
);

Каждый второй тег p получает class="red">

Пример № 4

each.call(document.querySelectorAll('p.blue'), 
    function(newClass, i) {
        if( i < 20 )
            this.className = newClass;
    }, 'green'
);

И, наконец, первые 20 синих тегов p заменены на зеленые

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

avatar
Rajesh Paul
25 декабря 2013 в 16:14
32

Существует три реализации foreach в jQuery, как показано ниже.

var a = [3,2];

$(a).each(function(){console.log(this.valueOf())}); //Method 1
$.each(a, function(){console.log(this.valueOf())}); //Method 2
$.each($(a), function(){console.log(this.valueOf())}); //Method 3
avatar
Federico Piragua
2 ноября 2013 в 02:23
32

Возможно, цикл for(i = 0; i < array.length; i++) - не лучший выбор. Почему? Если у вас это:

var array = new Array();
array[1] = "Hello";
array[7] = "World";
array[11] = "!";

Метод будет вызывать от array[0] до array[2]. Во-первых, это сначала будет ссылаться на переменные, которых у вас даже нет, во-вторых, у вас не будет переменных в массиве, а в-третьих, это сделает код более жирным. Вот что я использую:

for(var i in array){
    var el = array[i];
    //If you want 'i' to be INT just put parseInt(i)
    //Do something with el
}

И если вы хотите, чтобы это была функция, вы можете сделать это:

function foreach(array, call){
    for(var i in array){
        call(array[i]);
    }
}

Если хотите сломаться, немного логики:

function foreach(array, call){
    for(var i in array){
        if(call(array[i]) == false){
            break;
        }
    }
}

Пример:

foreach(array, function(el){
    if(el != "!"){
        console.log(el);
    } else {
        console.log(el+"!!");
    }
});

Возвращает:

//Hello
//World
//!!!
avatar
Micka
17 июля 2013 в 09:07
31

Простым решением было бы использовать библиотеку underscore.js. Он предоставляет множество полезных инструментов, таких как each, и автоматически делегирует задание родному forEach, если доступно.

Пример работы CodePen:

var arr = ["elemA", "elemB", "elemC"];
_.each(arr, function(elem, index, ar)
{
...
});

См. Также

avatar
nmoliveira
10 апреля 2013 в 00:26
37

A для каждой реализации (см. В jsFiddle):

function forEach(list,callback) {
  var length = list.length;
  for (var n = 0; n < length; n++) {
    callback.call(list[n]);
  }
}

var myArray = ['hello','world'];

forEach(
  myArray,
  function(){
    alert(this); // do something
  }
);
avatar
gaby de wilde
10 марта 2013 в 02:37
40

Если вы не против очистить массив:

var x;

while(x = y.pop()){ 

    alert(x); //do something 

}

x будет содержать последнее значение y и будет удалено из массива. Вы также можете использовать shift(), который предоставит и удалит первый элемент из y.

avatar
zzzzBov
17 февраля 2012 в 14:00
93

Некоторые языки стиля C используют foreach для циклического перебора перечислений. В JavaScript это делается с помощью структуры цикла for..in:

var index,
    value;
for (index in obj) {
    value = obj[index];
}

Тут есть загвоздка. for..in будет проходить по каждому из перечислимых членов объекта и членов его прототипа. Чтобы избежать чтения значений, которые наследуются через прототип объекта, просто проверьте, принадлежит ли свойство объекту:

for (i in obj) {
    if (obj.hasOwnProperty(i)) {
        //do stuff
    }
}

Кроме того, ECMAScript 5 добавил метод forEach к Array.prototype, который можно использовать для перечисления по массиву с помощью обратного вызова ( вы все еще можете использовать его для старых браузеров):

arr.forEach(function (val, index, theArray) {
    //do stuff
});

Важно отметить, что Array.prototype.forEach не прерывается, когда обратный вызов возвращает false. jQuery и Underscore.js предоставляют свои собственные варианты each для создания циклов, которые можно замкнуть накоротко.

avatar
joidegn
17 февраля 2012 в 13:58
28

Нет цикла for each в собственном JavaScript. Вы можете использовать библиотеки, чтобы получить эту функциональность (я рекомендую Underscore.js), или используйте простой цикл for in.

for (var instance in objects) {
   ...
}

Однако обратите внимание, что могут быть причины использовать еще более простой цикл for (см. Вопрос о переполнении стека Почему использование «for… in» с итерацией массива - такая плохая идея? )

var instance;
for (var i=0; i < objects.length; i++) {
    var instance = objects[i];
    ...
}
avatar
Quentin
17 февраля 2012 в 13:55
54

Если вы хотите перебрать массив, используйте стандартный трехэлементный цикл for.

for (var i = 0; i < myArray.length; i++) {
    var arrayItem = myArray[i];
}

Вы можете добиться некоторой оптимизации производительности, кэшируя myArray.length или повторяя его в обратном порядке.

avatar
PatrikAkerstrand
17 февраля 2012 в 13:55
551

Примечание : Этот ответ безнадежно устарел. Для более современного подхода посмотрите методы, доступные в массиве. Интересующие нас методы могут быть такими:

  • для каждого
  • карта
  • фильтр
  • почтовый индекс
  • уменьшить
  • каждые
  • некоторые

Стандартный способ перебора массива в JavaScript - это ванильный for -цикл:

var length = arr.length,
    element = null;
for (var i = 0; i < length; i++) {
  element = arr[i];
  // Do something with element
}

Обратите внимание, однако, что этот подход хорош только в том случае, если у вас есть плотный массив, и каждый индекс занят элементом. Если массив разреженный, то при таком подходе вы можете столкнуться с проблемами производительности, поскольку вы будете перебирать множество индексов, которые не действительно ​​существуют в массиве. В этом случае лучше использовать петлю for .. in. Однако необходимо использовать соответствующие меры предосторожности, чтобы гарантировать, что действуют только желаемые свойства массива (то есть элементы массива), поскольку цикл for..in также будет перечисляться в старых браузерах. , или если дополнительные свойства определены как enumerable.

В ECMAScript 5 в прототипе массива будет метод forEach, но он не поддерживается в устаревших браузерах. Таким образом, чтобы иметь возможность использовать его последовательно, вы должны либо иметь среду, которая его поддерживает (например, Node.js для серверного JavaScript), либо использовать «Polyfill». Однако полифил для этой функции является тривиальным и, поскольку он упрощает чтение кода, это хороший полифилл для включения.

stevec
5 сентября 2020 в 19:39
0

Есть ли способ сделать это одной строчкой кода. Например, в facebook мне нравится ускорять видео с помощью document.getElementsByTagName("video")[28].playbackRate = 2.2. Если бы я мог легко сопоставить все элементы, мне бы не пришлось определять, какое видео (например, индекс 28 в этом случае). Любые идеи?

PatrikAkerstrand
14 сентября 2020 в 06:24
2

@stevec: Array.from (document.querySelectorAll ('video')). forEach (видео => video.playbackRate = 2.2);