Питання Поворот через масив у JavaScript


У Java ви можете використовувати a for цикл для проходження об'єктів в масиві наступним чином:

String[] myStringArray = {"Hello", "World"};
for (String s : myStringArray)
{
    // Do something
}

Чи можете ви робити те ж саме в JavaScript?


2421
2018-06-10 00:04


походження


Гаразд, так що я трохи заплутався, добре використовувати розширену для циклу, коли ви отримуєте доступ до об'єктів? І використовувати для послідовного використання один? Це правильно? - Mark Szymanski
ні, це дійсно прості, об'єкти масиву мають числові покажчики, так що ви хочете ітерація над цими показниками в числовому порядку, послідовний цикл забезпечує, що розширено  for-in петля перераховує властивості об'єкта, без певного порядку, а також перераховує спадкові властивості ... для повторюється над масивами послідовних циклів завжди рекомендується ... - CMS
пов'язані - stackoverflow.com/questions/5349425/... - jondavidjohn
пов'язані - stackoverflow.com/q/6208964/31671 - alex
jsben.ch/#/Q9oD5 <= Ось тестовий набір рішень для циклічності через масиви - EscapeNetscape


Відповіді:


Використовуйте послідовність for петля:

var myStringArray = ["Hello","World"];
var arrayLength = myStringArray.length;
for (var i = 0; i < arrayLength; i++) {
    alert(myStringArray[i]);
    //Do something
}

@ zipcodeman пропонує використовувати for...in твердження, але для повторення масивів for-in слід уникати, ця заява має на меті перерахувати властивості об'єкта.

Його не слід використовувати для масивових об'єктів, оскільки:

  • Порядок ітерації не гарантується, індекси масивів не можуть бути відвідані в числовому порядку.
  • Спадкові властивості також перераховуються.

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

Наприклад:

Array.prototype.foo = "foo!";
var array = ['a', 'b', 'c'];

for (var i in array) {
  alert(array[i]);
}

Наведений вище код сповістить: "a", "b", "c" і "foo!".

Це буде особливо проблемою, якщо ви використовуєте деяку бібліотеку, яка дуже сильно залежить від віртуалізації власних прототипів (наприклад, MooTools).

The for-in Заява, як я вже сказав раніше, є перерахувати властивості об'єкта, наприклад:

var obj = {
  "a": 1,
  "b": 2,
  "c": 3
};

for (var prop in obj) {
  if (obj.hasOwnProperty(prop)) { 
  // or if (Object.prototype.hasOwnProperty.call(obj,prop)) for safety...
    alert("prop: " + prop + " value: " + obj[prop])
  }
}

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

Я б рекомендував вам прочитати наступну статтю:


3060
2018-06-10 00:07



Чому голосування? for...in має бути уникати для масивних об'єктів! - CMS
Це причина (за допомогою CMS він сам) stackoverflow.com/questions/1885317/... - OscarRyz
@DoubleGras, я думаю, що це думка, не поділена всіма. Побачити: stackoverflow.com/questions/5752906/... або groups.google.com/forum/?fromgroups#!topic/jsmentors/... - Matthijs Wessels
@StijndeWitt Ні, тому що він розбивається, якщо у вас є "помилковий" значення у вашому масиві: false, undefined, 0, "", NaN. - Phrogz
jsperf.com/caching-array-length/4  Ось тест, щоб побачити, чи варто кешувати довжину масиву в циклі Javascript - Enrico


Так, але тільки якщо ваша реалізація включає в себе for...of особливість введена в ECMAScript 2015 (випуск "Гармонія").

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

// 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 продовжують працювати в середовищі, де ще немає, - особливо, якщо писати код для роботи в веб-переглядачах, де розробники сайтів часто не можуть бути впевнені в тому, який браузер / версія їх клієнти будуть використовувати.

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

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

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

var i, s, myStringArray = [ "Hello", "World" ], len = myStringArray.length;
for (i=0; i<len; ++i) {
  if (i in myStringArray) {
    s = myStringArray[i];
    // ... do something with s ...
  }
}

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

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

var i, len, myStringArray = [ "Hello", "World" ];
for (len = myStringArray.length, i=0; i<len; ++i) {

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


871
2018-04-16 02:03



Зауважте, що деякі перекладачі (наприклад, V8) автоматично кешують довжину масиву якщо код називається достатньо разів, і він виявляє, що цикл не змінює довжину. Хоча кешування довжини все одно приємно, воно може не забезпечити швидкість прискорення, коли ваш код викликається достатньо разів, щоб дійсно змінити. - Phrogz
@ mark-reed Не могли б ви пояснити, чому ви використовували i in myStringArray у вашому прикладі? Як це може бути хибним? - Denis V
@ ДенісВ: помилково. a=[1,2,3,4]; delete a[2]; for (j in a) { console.log(j); }  виходи 0, 1, 3 та 4. a.lengthдосі 5. - Mark Reed
Я не пропоную for j in a. Я демонструю, що in перевірка не є зайвою, як ви стверджували це, показуючи всі індекси і показуючи, що є один між 0 і length-1 це не там. Я міг би також просто роздрукувати 2 in a, що справді є false, незважаючи на те, що ви сказали, що це було неможливо. - Mark Reed
@GrijeshChauhan - правильно. Наприклад, IE через версію 8 не підтримує його. Побачити це питання. - Mark Reed


Ви можете використовувати map, що є функціональним методом програмування, яке також доступне в інших мовах, як-от Python і Haskell.

[1,2,3,4].map( function(item) {
     alert(item);
})

Загальний синтаксис:

array.map(func)

В загальному func буде прийняти один параметр, який є елементом масиву. Але у випадку JavaScript це може мати другий параметр, який є індексом елемента, і третій параметр, який є самим масивом.

Повертає значення array.map це інший масив, тому ви можете використовувати його таким чином:

var x = [1,2,3,4].map( function(item) {return item * 10;});

І тепер X є [10,20,30,40].

Вам не потрібно написати функцію в рядку. Це може бути окремою функцією.

var item_processor = function(item) {
      // Do something complicated to an item
}

new_list = my_list.map(item_processor);

що буде подібним до:

 for (item in my_list) {item_processor(item);}

Крім того, ви не отримаєте new_list.


392
2018-06-10 00:09



Ні, але це може бути більш потужним. заціни: joelonsoftware.com/items/2006/08/01.html - hasen
Цей конкретний приклад, мабуть, краще реалізується за допомогою Array.forEach. map це для створення нового масиву. - harto
@hasen, the Array.prototype.map метод є частиною стандарту ECMAScript 5-го видання, ще не доступний для всіх реалізацій (наприклад, недоліків IE), також для повторюється над масивом я думаю, що Array.prototype.forEach метод більше семантично правильно ... також, будь ласка, не пропонуйте заяву про те, для чого більше, подивіться мою відповідь :) - CMS
Різниця між forEach і map є те, що перший не повертає результати ітерації. map (іноді a.k.a. collect, але дуже відрізняється від apply) - це явно для перетворення кожного елемента масиву у відповідний результат; це 1-до-1 відображення, звідси і назва. Це частина цілого сімейства операцій, які включають в себе reduce (який виробляє один результат з усього масиву) і filter (який виробляє підмножину вихідного масиву) і так далі. Враховуючи forEach просто робить щось з кожним елементом, семантика неуточнена. - Mark Reed
Вниз, тому що, якщо ви фактично нічого не називаєте, тоді використання [] .map вводить в оману. []. Для кожного робить семантичний сенс, а також передає ті ж три аргументи функції. - gengkev


У JavaScript не рекомендується цикл через масив з циклом for-in, але це краще використовувати для циклу, наприклад:

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

Це також оптимізовано ("кешування" довжини масиву). Якщо ви хочете дізнатись більше читати мою посаду на цю тему.


102
2017-12-07 07:24



myArray.forEach (функція (obj) ()); як і раніше найкраще - Jan Sverre
крихітне вдосконалення: можна використовувати ++i замість i++ - roberkules
++i це стара оптимізація школи, яку сучасні компілятори роблять для вас у циклі з давніх давніх :) stackoverflow.com/a/1547433/1033348 - ngryman
@ Янніс .forEach має декілька речей проти цього. 1) не рідний 2) Необхідний новий контекст виконання для КОЖНОГО індексу, який є досить дорогим і здається надмірним (див. dmitrysoshnikov.com/ecmascript/chapter-1-execution-contexts) - Jose
Ви повинні бути обережні, використовуючи цей цикл. Я почав використовувати його і мав важко відслідковувати помилку через одну помилку, яку я зробив. Якщо ви вкладете два цикли так: jsfiddle.net/KQwmL/1. Ви повинні бути обережними, щоб назвати var len інакше в двох циклах, інакше другий цикл перезаписує першу len. - Rui Marques


для (var s of myStringArray) {

(Прямий відповідь на ваше запитання: тепер ви можете!)

Більшість інших відповідей є правильними, але вони не згадують (з цього приводу) що Сценарій ECMA 6 2015 р приносить новий механізм для виконання ітерації for..of петля

Цей новий синтаксис є найбільш елегантним способом ітерації масиву в javascript (поки вам не потрібний індекс ітерації), але веб-переглядачі ще не підтримують його.

В даний час він працює з Firefox 13+, Chrome 37+, і він не спочатку працює з іншими браузерами (див. Сумісність браузера нижче). На щастя, у нас є компілятори JS (наприклад, Вавилон), які сьогодні дозволяють нам використовувати нові покоління.

Він також працює на вузлі (я протестував його в версії 0.12.0).

Ітератування масиву

// You could also use "let" instead of "var" for block scope.
for (var letter of ["a", "b", "c"]) { 
   console.log(letter); 
}

Ітератування масиву об'єктів

var band = [
  {firstName : 'John', lastName: 'Lennon'}, 
  {firstName : 'Paul', lastName: 'McCartney'}
];

for(var member of band){
  console.log(member.firstName + ' ' + member.lastName); 
}

Ітератування генератора:

(приклад витягнуто з https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of)

function* fibonacci() { // a generator function
  let [prev, curr] = [1, 1];
  while (true) {
    [prev, curr] = [curr, prev + curr];
    yield curr;
  }
}

for (let n of fibonacci()) {
  console.log(n);
  // truncate the sequence at 1000
  if (n >= 1000) {
    break;
  }
}

Таблиця сумісності: http://kangax.github.io/es5-compat-table/es6/#For..of loops

Spec:  http://wiki.ecmascript.org/doku.php?id=harmony:terator

}


92
2017-08-11 15:54



Якщо ви використовуєте ES6, я б запропонував const s замість var s - joeytwiddle


Тепер усі Opera, Safari, Firefox і Chrome поділяють набір покращених методів масиву для оптимізації багатьох звичайних циклів.

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

Mozilla Labs опублікував їх і алгоритми WebKit обидва використовуються, так що ви можете додати їх самі.

фільтр повертає масив предметів, які задовольняють певному стану чи тесту.

кожен повертає істину, якщо кожен учасник масиву проходить тест.

дещо повертає істину, якщо хтось проходить тест.

для кожного запускає функцію на кожному елементі масиву і нічого не повертає.

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

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

Ігнорувати це, поки не буде потрібним.

indexOf і lastIndexOf знайти правильну позицію першого або останнього елемента, який точно відповідає його аргументу.

(function(){
    var p, ap= Array.prototype, p2={
        filter: function(fun, scope){
            var L= this.length, A= [], i= 0, val;
            if(typeof fun== 'function'){
                while(i< L){
                    if(i in this){
                        val= this[i];
                        if(fun.call(scope, val, i, this)){
                            A[A.length]= val;
                        }
                    }
                    ++i;
                }
            }
            return A;
        },
        every: function(fun, scope){
            var L= this.length, i= 0;
            if(typeof fun== 'function'){
                while(i<L){
                    if(i in this && !fun.call(scope, this[i], i, this))
                        return false;
                    ++i;
                }
                return true;
            }
            return null;
        },
        forEach: function(fun, scope){
            var L= this.length, i= 0;
            if(typeof fun== 'function'){
                while(i< L){
                    if(i in this){
                        fun.call(scope, this[i], i, this);
                    }
                    ++i;
                }
            }
            return this;
        },
        indexOf: function(what, i){
            i= i || 0;
            var L= this.length;
            while(i< L){
                if(this[i]=== what)
                    return i;
                ++i;
            }
            return -1;
        },
        lastIndexOf: function(what, i){
            var L= this.length;
            i= i || L-1;
            if(isNaN(i) || i>= L)
                i= L-1;
            else
                if(i< 0) i += L;
            while(i> -1){
                if(this[i]=== what)
                    return i;
                --i;
            }
            return -1;
        },
        map: function(fun, scope){
            var L= this.length, A= Array(this.length), i= 0, val;
            if(typeof fun== 'function'){
                while(i< L){
                    if(i in this){
                        A[i]= fun.call(scope, this[i], i, this);
                    }
                    ++i;
                }
                return A;
            }
        },
        some: function(fun, scope){
            var i= 0, L= this.length;
            if(typeof fun== 'function'){
                while(i<L){
                    if(i in this && fun.call(scope, this[i], i, this))
                        return true;
                    ++i;
                }
                return false;
            }
        }
    }
    for(p in p2){
        if(!ap[p])
            ap[p]= p2[p];
    }
    return true;
})();

81
2018-06-10 02:43



Додатково: IE підтримує для кожного з версії 9, див для кожного методу MSDN - rwitzel


Використовуйте цикл while ...

var i=0, item, items = ['one','two','three'];
while(item = items[i++]){
    console.log(item);
}

журнали: "один", "два", "три"

І для зворотного порядку - ще більш ефективний цикл

var items = ['one','two','three'], i = items.length;
while(i--){
    console.log(items[i]);
}

журнали: "три", "два", "один"

Або класичний for петля

var items = ['one','two','three']
for(var i=0, l = items.length; i < l; i++){
    console.log(items[i]);
}

журнали: "один", "два", "три"

Довідка: http://www.sitepoint.com/google-closure-how-not-to-write-javascript/


62
2018-01-05 09:15



Перший приклад синтаксису "в той час як" не буде працювати, якщо який-небудь з елементів масиву є помилковим. - Chris Cooper
... і це цикл while еквівалентно: для (var i = 0, item; item = items [i]; i ++), що забирає необхідність оголосити індекс і змінні елемента заздалегідь ... - Stijn de Witt
@StijndeWitt Але для цього застосовується: якщо це значення falsy, це не спрацює... - yckart
Під час повторного збирання ви повинні дбати про оптимізацію. Оскільки це може вплинути на ефективність сторінки. - Zaheer Ahmed