Контакти

Перебір властивостей об'єктах. JQuery - Перебір масиву, об'єкта та елементів Явне використання ітератора

Це працює так:

// REQUIRES ECMASCRIPT 2015+ var s, myStringArray = ["Hello", "World"]; for (s of myStringArray) ( // ... do something with s ... )

Або ще краще, оскільки ECMAScript 2015 також надає змінні в області блоку за допомогою let і const:

// REQUIRES ECMASCRIPT 2015+ const myStringArray = ["Hello", "World"]; for (const s of myStringArray) ( // ... do something with s ... ) // s is no longer defined here

Примітка про розріджені масиви: масив JavaScript може фактично не зберігати стільки елементів, скільки зазначено в його length ; це повідомлення просто на одиницю більше, ніж найвищий індекс, при якому зберігається значення. Якщо масив містить менше елементів, ніж зазначено у його довжині, він називається розрідженим. Наприклад, цілком законно мати масив з елементами лише за індексами 3, 12 та 247; length такого масиву вказана як 248, хоча насправді він зберігає лише 3 значення. Якщо ви спробуєте отримати доступ до елемента за будь-яким іншим індексом, у масиву з'явиться undefined значення. Тому, коли ви хочете "перебрати" масив, у вас є питання, на яке потрібно відповісти: чи ви хочете перебрати весь діапазон, вказаний його довжиною, і обробити undefined для будь-яких пропущених елементів, або ви хочете обробити тільки елементи насправді подарунок? Існує безліч програм для обох підходів; це залежить тільки від того, навіщо ви використовуєте масив.

Якщо ви перебираєте масив за допомогою for .. of , тіло циклу виконується по length , а змінна керування циклом встановлюється undefined для будь-яких елементів, які насправді відсутні у масиві. Залежно від деталей вашого коду "що робити", така поведінка може бути тим, що ви хочете, але якщо це не те, що ви хочете, вам слід використовувати інший підхід.

Звичайно, деякі розробники не мають іншого вибору, крім використання іншого підходу в будь-якому випадку, тому що з якоїсь причини вони орієнтації версію JavaScript, який ще не підтримується for ... of .

Поки ваша реалізація JavaScript є сумісною з попередньою версією специфікації ECMAScript (яка, наприклад, виключає версії Internet Explorer до 9), ви можете використовувати метод ітератора Array#forEach замість циклу. У цьому випадку ви передаєте функцію, яка буде викликатись для кожного елемента в масиві:

Var myStringArray = ["Hello", "World"]; myStringArray.forEach(function(s) ( // ... do something with s ... ));

На відміну від for ... of , .forEach викликає функцію лише елементів, які насправді містять значення. Якщо передати наш гіпотетичний масив з трьома елементами та довжиною 248, він буде викликати функцію лише три рази, а не 248 разів. Він також розрізняє відсутні елементи та елементи, які насправді встановлені як undefined; Для останнього він як і раніше буде викликати функцію, передаючи як аргумент undefined значення. Якщо це, як ви хочете обробляти розріджені масиви, .forEach може бути шлях, навіть якщо ваш перекладач підтримує for ... of .

Останній варіант, який працює у всіх версіях JavaScript, – це явний цикл підрахунку. Ви просто вважаєте від 0 до одиниці менше довжини і використовуєте лічильник як індекс. Основний цикл виглядає так:

Однією з переваг цього підходу є те, що ви можете вибирати, як обробляти розріджені масиви; Наведений вище код буде запускати тіло циклу на повний length з s встановленим на undefined для будь-яких відсутніх елементів, як for .. of . Якщо замість цього ви хочете обробляти тільки реально існуючі елементи розрідженого масиву, такі як .forEach, ви можете додати in індекс просту перевірку:

Var i, s, myStringArray = ["Hello", "World"], len = myStringArray.length; for (i=0; i

Присвоєння значення довжини локальної змінної (на відміну включення повного висловлювання myStringArray.length за умов циклу) може істотно myStringArray.length на продуктивність, оскільки воно пропускає пошук властивостей щоразу остаточно; при використанні Rhino на моїй машині прискорення становить 43%.

Ви можете побачити, що кешування довжини виконується у пропозиції ініціалізації циклу, наприклад:

Var i, len, myStringArray = ["Hello", "World"]; for (len = myStringArray.length, i = 0; i

Згаданий іншими синтаксис for...in використовується для циклічного обходу властивостей об'єкта; Так як масив в JavaScript - це просто об'єкт з числовими іменами властивостей (і властивістю length, що автоматично оновлюється), ви можете теоретично зациклити масив з ним. Але проблема полягає в тому, що він не обмежується числовими значеннями властивостей (пам'ятаєте, що навіть методи насправді просто властивості, значення яких є замиканням), і при цьому не гарантується, що вони будуть повторюватися в числовому порядку. Отже, синтаксис for ... in не повинен використовуватися для циклічного переміщення масивами.

Вітаю! Продовжуємо вивчати методи масивів і у цьому уроці розглянемо методи для перебору масиву. Ці методи дозволяють пройтися масивом і виконати певні дії над його елементами. Так забув сказати всі ці методи не підтримуються в IE 8. Хоча так це вже зараз важливо що вони не підтримуються цим браузером, але все ж якщо хочете підтримку IE8, то ES5-shim вам в допомогу. А ми продовжуватимемо

Метод forEach

Даний метод використовується для проходу масивом в циклі, але йому можна передати функцію, в якій можна робити певні дії над елементами масиву. Розглянемо з прикладу.

Var mas = ["Банан", "Авокадо", "Морква"]; mas.forEach(function(item, i, mas) ( alert(i + ": " + item + " (масив:" + mas + ")"); ));

Тут у прикладі в метод forEach передається функція в якій вказується 3 параметри:

item- Елемент масиву

i- Номер елементу масиву

mas- Масив, який обробляється.

Даний метод можна використовувати замість циклу для перебору масиву.

Метод filter

Цей метод також як і метод forEach використовується для перебору масиву і йому передається функція як аргумент, але він дозволяє фільтрувати масив і повертає новий масив, куди потрапляють лише ті елементи для яких функція, яку ми передаємо в цей метод, поверне true.

Трохи заплутано, тож розглянемо на прикладі.

Var mas =; var positiveNum = mas.filter(function(num) ( return num > 0; )); document.write(positiveNum); // 1,4,3

У прикладі є масив із числами і нам треба отримати інший масив, в якому були б лише позитивні числа з вихідного масиву. Для цього до масиву застосовуємо метод filter і викликаємо функцію, яка перевірятиме кожен елемент, тобто вона поверне всі позитивні числа, а результат буде зберігатися в іншому масиві в прикладі це positiveNum.

Метод map

Метод map створює інший масив, який буде складатися з результатів виклику функції вихідного масиву, але в цій функції над елементами вихідного масиву відбуватимуться якісь дії і результат виявиться в новому масиві як. Давайте розберемо приклад, бо я думаю зовсім незрозуміло.

Var mas =; var newMas = mas.map(function(item) ( return item*item; )); // отримали масив із квадратами alert(newMas); // 1,4,9

У прикладі є вихідний масив з числами до нього застосовується метод map, в якому кожен елемент масиву множиться сам на себе і результат записується в інший масив. У результаті отримаємо масив із квадратами чисел вихідного масиву.

Методи every/some

Дані методи перевіряють присутній елемент у масиві. Роблять вони це через функцію, яка їм передається як параметр, тобто якщо ця функція поверне true, тоді і сам метод поверне true. Причому метод every вимагає, щоб кожен елемент відповідав умові функції, а метод some, щоб хоча б один відповідав. І як завжди ось вам приклад.

Var mas =; function isPositiv(num) ( return num > 0; ) if(mas.every(isPositiv)) ( document.write("Масив містить тільки позитивні числа"); ) else( document.write("У масиві є хоча б одне негативне число "); ) if(mas.some(isPositiv)) ( document.write("У масиві є хоча б одне позитивне число"); ) else ( document.write("У масиві немає позитивних чисел"); )

Розглянемо приклад у нас є масив із позитивними та негативними числами і нам треба перевірити його на наявність хоча б одного негативного числа. Для цього використовуємо методи every та some. Створюємо функцію, яка повертатиме позитивні числа і потім її передаємо в метод every оскільки даний метод повертає логічний результат, то використовується він в умовних операторах. Метод every у нашому прикладі поверне false тому що в масиві є негативні числа, а ось метод some поверне true, тому що в масиві є хоча б одне позитивне число.

reduce/reduceRight

Якщо вам потрібно перебрати масив – ви можете використовувати forEach, for або for..of.

Якщо вам потрібно перебрати масив і повернути дані для кожного елемента, ви використовуєте map.

Методи arr.reduceі arr.reduceRightсхожі на методи вищі, але вони трішки складніші. Вони використовуються для обчислення якогось одного значення на основі всього масиву.

Синтаксис:

Let value = arr.reduce(function(previousValue, item, index, array) ( // ... ), );

Функція застосовується по черзі до всіх елементів масиву і переносить свій результат на наступний виклик.

Аргументи:

  • previousValue – результат попереднього виклику цієї функції, дорівнює initial при першому виклику (якщо передано initial),
  • item – черговий елемент масиву,
  • index – його індекс,
  • Array – сам масив.

При виклику функції результат її виклику попередньому елементі масиву передається як аргумент.

Звучить складно, але все стає простіше, якщо думати про перший аргумент як результат, що «акумулює» попередніх викликів функції. Після закінчення він стає результатом зменшення.

Цей метод найпростіше зрозуміти як завжди на прикладі.

Тут ми отримаємо суму всіх елементів масиву лише одним рядком:

Let arr =; let result = arr.reduce((sum, current) => sum + current, 0); alert(result); // 15

Тут ми використовували найпоширеніший варіант reduce, який використовує лише 2 аргументи.

Давайте детальніше розберемо, як він працює.

  1. При першому запуску sum дорівнює initial (останній аргумент reduce), тобто 0, а current - перший елемент масиву, що дорівнює 1. Таким чином, результат функції дорівнює 1.
  2. При другому запуску sum = 1 і до нього ми додаємо другий елемент масиву (2).
  3. У третьому запуску sum = 3, до якого ми додаємо наступний елемент, тощо…

Потік обчислень виходить такий:

У вигляді таблиці, де кожен рядок – виклик функції на черговому елементі масиву:

sum current result
перший виклик 1 1
другий виклик 1 2 3
третій виклик 3 3 6
четвертий виклик 6 4 10
п'ятий виклик 10 5 15

Тут виразно видно, як результат попереднього виклику передається до першого аргументу наступного.

Ми також можемо опустити початкове значення:

Let arr =; // прибрано початкове значення (немає 0 наприкінці) let result = arr.reduce((sum, current) => sum + current); alert(result); // 15

Результат – такий самий! Це тому, що за відсутності initial як одне значення береться перший елемент масиву, а перебір стартує з другого.

Таблиця обчислень буде такою самою за вирахуванням першого рядка.

Але таке використання потребує надзвичайної обережності. Якщо масив є порожнім, то виклик reduce без початкового значення видасть помилку.

Ось приклад:

Let arr =; // Error: Reduce of empty array with no initial value // Якби існувало початкове значення, reduce повернув його для порожнього масиву. arr.reduce((sum, current) => sum + current);

Підсумки

Отже підіб'ємо підсумки ми розглянули різні методи для роботи з масивами в циклі у всіх цих методів є одне спільне те, що всім їм треба передавати функцію в якості аргументу.

  • forEach – для перебору масиву у циклі.
  • filter – здійснення фільтрації масиву. Повертає новий відфільтрований масив
  • every/some – для перевірки масиву щодо присутності окремих елементів.
  • map – для перетворення масиву на масив. Повертає вихідний перетворений масив.
  • reduce/reduceRight — обчислює одне значення всього масиву, викликаючи функцію кожного елемента і передаючи проміжний результат між викликами. Можна використовувати для розрахунку суми елементів масиву.

Завдання

Отримайте новий масив

Нехай даний масив var mas = ["HTML", "CSS", "JavaScript", "Pascal"] вам треба за допомогою методу map отримати новий масив, який буде містити довжини кожного елемента вихідного масиву.

Відфільтруйте масив

Є масив var mas = вам потрібно, використовуючи метод filter отримати масив, який містить лише позитивні числа.

Перевірити масив

Є масив var mas = вам треба перевірити, чи є в масиві негативні числа і вивести результат на екран.

Ну і на завершення невелике відео за методами для перебору масиву в циклі.

  • Переклад
  • I. Перебір реальних масивів
    1. Метод forEach і споріднені методи
    2. Цикл for
    3. Правильне використання циклу for...in
    4. Цикл for...of (неявне використання ітератора)
    5. Явне використання ітератора
    1. Використання способів перебору справжніх масивів
    2. Перетворення на справжній масив
    3. Зауваження щодо об'єктів середовища виконання

I. Перебір реальних масивів

На даний момент є три способи перебору елементів цього масиву:
  1. метод Array.prototype.forEach;
  2. класичний цикл for;
  3. «правильно» побудований цикл for...in.
Крім того, незабаром, з появою нового стандарту ECMAScript 6 (ES 6), очікується ще два способи:
  1. цикл for...of (неявне використання ітератора);
  2. явне використання ітератора.

1. Метод forEach і споріднені методи

Якщо ваш проект розрахований на підтримку можливостей стандарту ECMAScript 5 (ES5), можна використовувати одне з його нововведень - метод forEach .

Приклад використання:
var a = ["a", "b", "c"]; a.forEach(function(entry) ( console.log(entry); ));
У загальному випадку використання forEach потребує підключення бібліотеки емуляції es5-shim для браузерів, які не мають нативної підтримки цього методу. До них відносяться IE 8 і раніше версії, які до цих пір де-не-де ще використовуються.

До переваг дляEach відноситься те, що тут не потрібно оголошувати локальні змінні для зберігання індексу та значення поточного елемента масиву, оскільки вони автоматично передаються у функцію зворотного виклику (колбек) як аргументи.

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

ForEach призначений для перебору всіх елементів масиву, але крім нього ES5 пропонує ще кілька корисних методів для перебору всіх або деяких елементів плюс виконання при цьому будь-яких дій з ними:

  • every - повертає true, якщо для кожного елемента масиву колбек повертає значення, що приводиться до true.
  • some-повертає true, якщо хоча б для одного елемента масиву колбек повертає значення, що приводиться до true.
  • filter - створює новий масив, що включає елементи вихідного масиву, для яких колбек повертає true .
  • map - створює новий масив, що складається зі значень колбеком, що обертаються.
  • reduce - зводить масив до єдиного значення, застосовуючи колбек по черзі до кожного елемента масиву, починаючи з першого (може бути корисним для обчислення суми елементів масиву та інших підсумкових функцій).
  • reduceRight – працює аналогічно reduce, але перебирає елементи у зворотному порядку.

2. Цикл for

Старий добрий for рулит:

Var a = ["a", "b", "c"]; var index; for (index = 0; index< a.length; ++index) { console.log(a); }
Якщо довжина масиву незмінна протягом усього циклу, а сам цикл належить критичній у плані продуктивності ділянці коду (що малоймовірно), то можна використовувати більш оптимальну версію for зі зберіганням довжини масиву:

Var a = ["a", "b", "c"]; var index, len; for (index = 0, len = a.length; index< len; ++index) { console.log(a); }
Теоретично цей код має виконуватися трохи швидше, ніж попередній.

Якщо порядок перебору елементів не важливий, то можна піти ще далі в плані оптимізації та позбутися змінної для зберігання довжини масиву, змінивши порядок перебору на зворотний:

Var a = ["a", "b", "c"]; var index; for (index = a.length - 1; index >= 0; --index) ( console.log(a); )
Тим не менш, у сучасних движках JavaScript подібні ігри з оптимізацією зазвичай нічого не означають.

3. Правильне використання циклу for...in

Якщо вам порадять використовувати цикл for ... in, пам'ятайте, що перебір масивів - не те, для чого він призначений. Попри поширену оману цикл for...in перебирає не індекси масиву, а перераховані властивості об'єкта.

Тим не менш, у деяких випадках, таких як перебір розріджених масивів , for ... in може виявитися корисним, якщо тільки дотримуватися при цьому запобіжних заходів, як показано в прикладі нижче:

// a - розріджений масив var a =; a = "a"; a = "b"; a = "c"; for (var key in a) ( if (a.hasOwnProperty(key) && /^0$|^\d*$/.test(key) && key<= 4294967294) { console.log(a); } }
У цьому прикладі кожної ітерації циклу виконується дві перевірки:

  1. те, що масив має власну властивість з ім'ям key (не успадковане з його прототипу).
  2. те, що key - рядок, що містить десятковий запис цілого числа, значення якого менше 4294967294 . Звідки береться останнє число? З визначення індексу масиву ES5, з якого випливає, що найбільший індекс, який може мати елемент в масиві: (2^32 - 2) = 4294967294 .
Звичайно, такі перевірки заберуть зайвий час під час виконання циклу. Але у разі розрідженого масиву цей спосіб ефективніший, ніж цикл for, оскільки в цьому випадку перебираються ті елементи, які явно визначені в масиві. Так, у прикладі вище буде виконано всього 3 ітерації (для індексів 0, 10 та 10000) - проти 10001 у циклі for .

Щоб не писати такий громіздкий код перевірок щоразу, коли потрібно перебір масиву, можна оформити його у вигляді окремої функції:

Function arrayHasOwnIndex(array, key) ( return array.hasOwnProperty(key) && /^0$|^\d*$/.test(key) && key<= 4294967294; }
Тоді тіло циклу із прикладу значно скоротиться:

For (key in a) ( if (arrayHasOwnIndex(a, key))) ( console.log(a); ) )
Розглянутий вище код перевірок є універсальним, придатним всім випадків. Але замість нього можна використовувати більш коротку версію, хоча формально і не зовсім правильну, проте, придатну для більшості випадків:

For (key in a) ( if (a.hasOwnProperty(key) && String(parseInt(key, 10)) === key) ( console.log(a); ) )

4. Цикл for...of (неявне використання ітератора)

ES6, поки все ще перебуває в статусі чернетки, повинен ввести JavaScript ітератори.

Ітератор - це реалізований об'єктом протокол, який визначає стандартний спосіб отримання послідовності значень (кінцевої чи нескінченної).
Ітератор - це об'єкт, у якому визначено метод next() - функція без аргументів, що повертає об'єкт із двома властивостями:

  1. done (boolean) - приймає значення true , якщо ітератор досяг кінця послідовності, що ітерується. В іншому випадку має значення false.
  2. value - визначає значення, яке повертається ітератором. Можливо не визначено (відсутня), якщо властивість done має значення true .
Багато вбудованих об'єктів, у т.ч. справжні масиви мають ітератори за замовчуванням. Найпростіший спосіб застосування ітератора у справжніх масивах - використовувати нову конструкцію for...of.

Приклад використання for...of:

Var val; var a = ["a", "b", "c"]; for (val of a) (console.log(val); )
У наведеному прикладі цикл for...of неявно викликає ітератор об'єкта Array щоб одержати кожного значення масиву.

5. Явне використання ітератора

Ітератори можна також використовувати і явно, щоправда, у цьому випадку код стає значно складнішим, порівняно з циклом for...of. Виглядає це приблизно так:

Var a = ["a", "b", "c"]; var it = a.entries(); var entry; while (!(entry = it.next()).done) ( console.log(entry.value); )
У цьому прикладі метод Array.prototype.entries повертає ітератор, який використовується для виведення значень масиву. На кожній ітерації entry.value міститься масив виду [ключ, значення] .

ІІ. Перебір масивоподібних об'єктів

Крім справжніх масивів, JavaScript зустрічаються також масивоподібні об'єкти . Зі справжніми масивами їх ріднить те, що вони мають властивість length і властивості з іменами у вигляді чисел, що відповідають елементам масиву. Як приклади можна назвати DOM колекції NodeList і псевдомасив arguments, доступний всередині будь-якої функції/методу.

1. Використання способів перебору реальних масивів

Як мінімум більшість, якщо не всі способи перебору справжніх масивів можуть бути застосовані для перебору масивоподібних об'єктів.

Конструкції for і for...in можуть бути застосовані до масивоподібних об'єктів точно тим самим шляхом, що і до масивів.

ForEach та інші методи Array.prototype також застосовуються до масивоподібних об'єктів. Для цього потрібно використовувати виклик Function.call або Function.apply.

Наприклад, якщо ви хочете застосувати forEach до властивості childNodes об'єкта Node , то це робиться так:

Array.prototype.forEach.call(node.childNodes, function(child) ( // робимо що-небудь з об'єктом child));
Для зручності повторного використання цього прийому, можна оголосити посилання на метод Array.prototype.forEach в окремій змінній та використовувати його як скорочення:

// (передбачається, що весь код нижче знаходиться в одній області видимості) var forEach = Array.prototype.forEach; // ... forEach.call(node.childNodes, function(child) ( // робимо що-небудь з об'єктом child));
Якщо масивоподобном об'єкті є ітератор, його можна використовувати явно чи неявно для перебору об'єкта так само, як і справжніх масивів.

2. Перетворення на справжній масив

Є також ще один, дуже простий спосіб перебору масивоподібного об'єкта: перетворити його в справжній масив і використовувати будь-який з розглянутих вище способів перебору справжніх масивів. Для перетворення можна використовувати універсальний метод Array.prototype.slice, який може бути застосований до будь-якого масивного об'єкта. Робиться це дуже просто, як показано на прикладі нижче:

Var trueArray = Array.prototype.slice.call(arrayLikeObject, 0);
Наприклад, якщо ви хочете перетворити колекцію NodeList на справжній масив, вам потрібен приблизно такий код:

Var divs = Array.prototype.slice.call(document.querySelectorAll("div"), 0);
Update: Як було зазначено у коментарях

12 Бер 2016

У сучасному JavaScript існують, так звані методи, що «перебирають», які застосовуються для перебору масивів. У цьому уроці ми розглянемо такі методи:

forEach

Метод.forEach() використовується для переборумасиву. Він викликає так звану функцію callback, за допомогою якої надається три параметри item, i, arr, де:

  • item – елемент масиву;
  • i - порядковий номер масиву;
  • arr - сам масив, який повинен перебиратися.

Щоб простіше було зрозуміти, як використовувати цей метод, розглянемо приклад:

Var user=["admin","pass",31]; user.forEach(function(item,i,user)( alert("Значення елемента за № " + i + " : " + item); ));

Цей метод можна використовувати замість звичайного циклу for.

filter

Метод.filter() використовується для фільтрації, він також використовує функцію callback, але створює новий масив, якщо елементи в масиві підходять під значення true:

Var arr =; var newArr=arr.filter(function(number)( return number< 0; }); alert(newArr); // выведет -34,-4

У цьому прикладі перевіряються числа негативні значення, але в виході виводиться новий масив із цими значеннями. Ви можете вигадати свої умови, зовсім необов'язково це повинні бути числа.

every/some

Ці два методи схожі один з одним і обидва використовуються для перевірки масиву, тільки метод .every()повертає значення true якщо всі значення масиві підходять під задану умову, а метод .some()повертає true якщо хоча б одне значення підходить під умову:

Var arr =; alert(arr.every(function(number)( return number)< 0; })); // выведет false

Сподіваюся зрозуміло, що якби у прикладі вище використовувався метод someто в нас вивелося б значення true, замість false.

map

Метод.map() трансформує масив та отримує з нього новий. Все робиться за допомогою виклику callback-функції:

Var arr =; var newArr=arr.map(function(number)( return number*2; )); alert(newArr);

У цьому прикладі ми отримали новий масив із подвоєними значеннями елементів.

reduce/reduceRight

Останні методи, які ми з вами розглянемо це reduce і reduceright. Використовуються для обробки кожного елемента масиву зі збереженням проміжного результату. Метод перебирає кожен елемент зліва направо, зменшуючиправоруч навпаки. На відміну від інших методів, крім функції callback, тут ще вказується аргумент initialValue — «початкове значення». Плюс до всього функції callback вказується «проміжний результат» - previousValueі currentItem- поточний елемент масиву.

Давайте розглянемо приклад:

Function getSums(arr) ( var result = ; if (!arr.length) return result; var totalSum = arr.reduceRight(function(sum, item) ( result.push(sum); return sum + item; )); .push(totalSum); return result; // 1,3,6,10,15

Що сталося у цьому прикладі? Ми створили функцію, яка дозволяє отримати новий масив із елементами, створеними із суми попередніх. Причому, звіт елементів йде з кінця. А ось більш простий приклад, в якому я створив функцію, що вважає суму елементів у масиві:

Function getSum(arr) ( var result = arr.reduce(function(sum, current) ( return sum + current )); return result; ); alert(getSum()); Теги: 

22 відповіді

Після виконання цього тесту з більшістю сучасних браузерів...

В даний часнайшвидша форма циклу (і, як на мене, найбільш синтаксично очевидна).

стандарт для циклу з кешуванням за довжиною

For (var i = 0, len = myArray.length; i< len; i++) { }

Я б сказав, що це безперечно випадок, коли я вітаю розробників движка JavaScript. Час виконання має бути оптимізовано для ясності, а не для зручності.

Станом на червень 2016 року, кілька тестів в останньому Chrome (71% ринку браузерів у травні 2016 року та збільшення):

  • Найшвидший цикл – це цикл циклуяк з довжиною кешування, так і без нього, що забезпечує дуже схожу продуктивність. (Цикл for з кешованою довжиною іноді дає кращі результати, ніж той, що не кешується, але різниця майже незначна, а це означає, що двигун може бути оптимізований на користь стандартного і, можливо, найпростішого циклу без кешування).
  • Цикл while з декрементами був приблизно 1,5 разу повільніше, ніж цикл for.
  • Цикл з використанням функції зворотного виклику (наприклад, standard forEach) був приблизно в 10 разів повільніший, ніж цикл for.

Я вважаю, що цей потік занадто старий, і програмісти вважають, що їм потрібно кешувати довжину, або використовувати зворотні перетину зі зменшенням, щоб домогтися більшої продуктивності, написання коду, який є менш розбірливим і більш схильним до помилок, ніж простий для циклу. Тому я рекомендую:

    Якщо ваша програма повторює безліч елементів або ваш код циклу знаходиться всередині функції, яка використовується часто, прямий цикл є відповіддю:

    For (var i = 0; i< arr.length; i++) { // Do stuff with arr[i] or i }

    Якщо ваша програма дійсно не перебирає безліч елементів або вам просто потрібно робити невеликі ітерації тут і там, використання стандартного зворотного виклику forEach або будь-якої подібної функції з обраної вами бібліотеки JS може бути більш зрозумілим і менш схильний до помилок, оскільки область змінних індексу закрита, і вам не потрібно використовувати дужки, що безпосередньо звертаються до значення масиву:

    Arr.forEach(function(value, index) ( // Do stuff with value or index ));

    Якщо вам дійсно потрібно пом'яти кілька мілісекунд, ітерації по мільярдах рядків, і довжина масиву не зміниться в процесі, ви можете подумати про довжину кешування в циклі for. Хоча я думаю, що в наші дні це справді не потрібно:

    For (var i = 0, len = arr.length; i< len; i++) { // Do stuff with arr[i] }

Це просто 2018, так що оновлення може бути гарним...

І я дійсно повинен не погодитися з прийнятою відповіддю. Це залежить від різних браузерів. деякі роблять forEach швидше, деякі for-loop , а деякі while тестують всі методи http://jsben.ch/mW36e

Arr.forEach(a => ( // ... )

і так як ви можете побачити безліч циклів for(a = 0;...) наприклад, for(a = 0;...) то варто згадати, що без змінних "var" буде визначатися глобально, і це може суттєво вплинути на швидкість, тому вона буде повільною.

var arr = arr = new Array(11111111).fill(255); var benches = [["empty", () =>< l; a++); }] , ["for-loop", () =>( for(var a = 0, l = arr.length; a< l; ++a) var b = arr[a] + 1; }] , ["for-loop++", () =>( for(var a = 0, l = arr.length; a< l; a++) var b = arr[a] + 1; }] , ["for-loop - arr.length", () =>( for (var a = 0; a< arr.length; ++a) var b = arr[a] + 1; }] , ["reverse for-loop", () =>( for(var a = arr.length - 1; a >= 0; --a) var b = arr[a] + 1; )] ,["while-loop", () => ( var a = 0 , l = arr.length;< l) { var b = arr[a] + 1; ++a; } }] , ["reverse-do-while-loop", () =>( var a = arr.length - 1; // CAREFUL do ( var b = arr[a] + 1; ) while(a--); )] , ["forEach", () => ( arr.forEach( a => ( var b = a + 1; )); ; for(const a in ar) ( var b = a + 1; ) )] , ["Duff device", () => ( var i = 0; var r = arr.length % 8; var n = (arr .length - r) / 8; if (r > 0) do (var b = arr + 1; ) while (--r); if (n > 0) do (var b = arr [i] + 1; c = arr + 1; var d = arr + 1; --n >>> 3; ) while (n); ], ["Duff device negative", () => ( var r = arr.length % 8; var n = (arr.length-r) / 8 ; ///Math.floor(arr.length / 8); (n) (var b = arr [i] + 1; var c = arr + 1; var d = arr + 1; var e = arr + 1; var f = arr + 1; var g = arr + 1; var h = arr + 1; var j = arr + 1; function bench(title, f) ( var t0 = performance.now(); var res = f(); return performance.now() - t0; // console.log("$(title) took $(t1-t0) ) msec"); ) var globalVarTime = bench("for-loop without "var"", () => ( // Тут ви знайдете "Var" з параметрами"ll be global for(a = 0, l = arr.length;< l; ++a) var b = arr[a] + 1; }); var times = benches.map(function(a) { arr = new Array(11111111).fill(255); return }).sort((a,b) =>a-b); var max = times; times = times.map(a => (a = (a/max)*100; return a; )); var template = (title, time, n) => "

" + "$(title) " + " $(Number(time.toFixed(3)))msec" + "
var strRes = times.map(t => template(...t)).join("\n") + "

for-loop без "var" $(globalVarTime) msec."; var $container = document.getElementById("container"); $container.innerHTML = strRes; body ( color:#fff; background:#333; font-family :helvetica; ) body > div > div ( clear:both ) body > div > div > span ( float:left; width:43%; margin:3px 0; text-align:right; ) body > div > div > span :nth-child(2) ( text-align:left; background:darkorange; animation:showup .37s .111s; -webkit-animation:showup .37s .111s; ) @keyframes showup ( from ( width:0; ) ) @-webkit-keyframes showup ( from ( width:0; ) )

2014 While тому

Подумайте логічно.

Подивіться на це

For(var index = 0 , length = array.length ; index< length ; index++) { //do stuff }

  • Необхідно створити щонайменше 2 змінних (індекс, довжина)
  • Необхідно перевірити, чи менший покажчик довжини
  • Необхідно збільшити індекс
  • цикл for має 3 параметри

Тепер скажіть мені, чому це має бути швидше, ніж:

Var length = array.length; while(--length) ( //or length-- //do stuff )

  • Одна змінна
  • Немає перевірок
  • індекс зменшується (машини воліють це)
  • While має лише один параметр

Я був повністю спантеличений, коли Chrome 28 показав, що цикл for працює швидше, ніж час. Це має бути якось

"Ну кожен використовує цикл for, нехай фокусується на цьому, коли для хром ".

Але тепер, у 2014 році, цикл while повертається на хром. він у 2 рази швидше, в інших/старих браузерах він завжди був швидшим.

Останнім часом я зробив кілька тестів. Тепер у реальному світі envoirement ці короткі коди нічого не варті, і jsperf не може фактично правильно виконати цикл while, тому що йому потрібно відтворити array.length, що також вимагає часу.

НЕ МОЖЕ отримати фактичну швидкість циклу, коли на jsperf.

вам потрібно створити свою власну функцію та перевірити, що за допомогою window.performance.now()

І так... немає ніякого способу, щоб цикл while був швидше.

Реальна проблема - це фактичне маніпулювання/час відтворення/час малювання або ви хочете називати його.

Наприклад, у мене є сцена canvas, де мені потрібно обчислити координати та колізії... це робиться між 10-200 MicroSeconds (не мілісекундами). він фактично приймає різні мілісекунди, щоб зробити все. Так само, як у DOM.

У деяких випадках існує ще один суперефективний спосіб використання loop ... наприклад, для копіювання/клонування масиву

For(var i = array.length ; i > 0 ; arrayCopy [--i] = array [i] // doing stuff);

Зверніть увагу на налаштування параметрів:

  • Те саме, що й у циклі while. Я використовую лише одну змінну
  • Необхідно перевірити, чи більше індекс більше 0;
  • Як ви можете бачити, цей підхід відрізняється від звичайного циклу, який кожен використовує, оскільки я роблю матеріал всередині 3-го параметра, а також зменшую безпосередньо всередині масиву.

Сказано, що це підтверджує, що машини, такі як

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

For(var i = array.length ; i-- ; arrayCopy [i] = array [i] // doing stuff);

Навіть якщо це коротше, схоже, що використання ще раз уповільнює все. Це на 1/5 повільніше за попередній цикл for і While.

Примітка:; дуже важливо після того, як для looo без ()

Навіть якщо я тільки-но сказав вам, що jsperf - це не найкращий спосіб протестувати скрипти. Я додав тут 2 цикли.

І ось ще одна відповідь про продуктивність у javascript

Ця відповідь має показати виконавчі способи написання JavaScript. Тому, якщо ви не можете прочитати це, запитайте і ви отримаєте відповідь або прочитаєте книгу про javascript http://www.ecma-international.org/ecma-262/5.1/

Остання ревізія тесту, яку я підготував (шляхом повторного використання старішого), показує одну річ.

Довжина кешування не така важлива, але це не шкодить.

Кожен перший запуск тесту, пов'язаного вище (на вкладці, що недавно відкрилася), дає найкращі результати для останніх 4 фрагментів (3-й, 5-й, 7-й і 10-й в діаграмах) в Chrome, Opera і Firefox на моєму 64- бітному Debian Squeeze (моє настільне обладнання). Наступні прогони дають зовсім інший результат.

Висновки щодо продуктивності прості:

  • Перейдіть в цикл for (вперед) та перевірте за допомогою!== замість< .
  • Якщо вам не потрібно повторно використовувати масив пізніше, тоді також ефективний цикл із зменшеною довжиною та деструктивним масивом shift() -ing.

В даний час (2011.10) нижче шаблон виглядає як найшвидший.

For (var i = 0, len = arr.length; i !== len; i++) ( ... )

Пам'ятайте, що кешування arr.length тут не має вирішального значення, тому ви можете просто протестувати i !== arr.length , і продуктивність не знизиться, але ви отримаєте коротший код.

PS: Я знаю, що у фрагменті з shift() його результат можна використовувати замість доступу до 0-го елементу, але я чомусь забував, що після повторного використання попередньої ревізії (яка мала неправильне значення під час циклів), а пізніше я не хотів втрачати вже отримані результати.

"Найкращий", як у чистому виконанні? або продуктивність І?

Чиста продуктивність "найкраща" - це те, що використовує кеш та префіксний оператор ++ (мої дані: http://jsperf.com/caching-array-length/189)

For (var i = 0, len = myArray.length; i< len; ++i) { // blah blah }

Я б сказав, що цикл без кешу - найкращий баланс часу виконання та часу читання програміста. Кожен програміст, що починається з C/C++/Java, не витрачатиме мс, щоб прочитати цей

For(var i=0; i< arr.length; i++){ // blah blah }

** Кешуйте довжину масиву всередині циклу, деякі секунди часу будуть вислизати. Залежить від елементів у масиві, якщо в масиві є більше елементів, існує велика різниця щодо Ms часу *

SArr; // Array; for(var i = 0; i

SArr; // Array; for(var i = 0,len = sArr.length ; i< len ; i++) { callArray(sArr[i]); //function call } ***end: 1.354ms***

Це рік 2017 .

Я зробив кілька тестів.

Схоже, метод while є найшвидшим у Chrome.

Схоже, що лівий декремент (--i) набагато швидше за інших (++i, i--, i++) в Firefox.

Цей підхід є постом у середньому. Але він виконує ітерацію масиву у зворотному порядку.

Let i = array.length; while (--i >= 0) ( doSomething(array[i]); )

Якщо пріоритетний порядок є важливим, використовуйте цей підхід.

Let ii = array.length; let i = 0; while (i< ii) { doSomething(array[i]); ++i; }

Я завжди пишу у першому стилі.

Навіть якщо компілятор досить розумний, щоб оптимізувати його для масивів, але все ж таки він розумний, якщо ми використовуємо DOMNodeList тут або якийсь складний об'єкт з розрахованою довжиною?

Я знаю, що питання про масиви, але я вважаю гарною практикою писати всі ваші петлі в одному стилі.

Var arr =; // The array var i = 0; while (i< arr.length) { // Do something with arr[i] i++; }

i ++ швидше, ніж ++ i, --i і я -



Сподобалася стаття? Поділіться їй