JavaScript для... в vs для
Считаете ли вы, что существует большая разница для... внутри и для циклов? Какую "для" вы предпочитаете использовать и почему?
Скажем, у нас есть массив ассоциативных массивов:
var myArray = [{'key': 'value'}, {'key': 'value1'}];
Итак, мы можем выполнить итерацию:
for (var i = 0; i < myArray.length; i++)
и
for (var i in myArray)
Я не вижу большой разницы. Есть ли проблемы с производительностью?
Ответы
Ответ 1
Выбор должен основываться на том, какой идиом лучше всего понять.
Массив повторяется с помощью:
for (var i = 0; i < a.length; i++)
//do stuff with a[i]
Объект, используемый в качестве ассоциативного массива, повторяется с использованием:
for (var key in o)
//do stuff with o[key]
Если у вас нет причин для разрушения земли, придерживайтесь установленной схемы использования.
Ответ 2
Дуглас Крокфорд рекомендует в JavaScript: Хорошие части (стр. 24), чтобы избежать использования оператора for in
.
Если вы используете for in
для перебора имен свойств в объекте, результаты не упорядочиваются. Хуже: вы можете получить неожиданные результаты; он включает в себя элементы, унаследованные от цепи прототипа и имя методов.
Все, кроме свойств, можно отфильтровать с помощью .hasOwnProperty
. Этот пример кода делает то, что вы, возможно, хотели первоначально:
for (var name in obj) {
if (Object.prototype.hasOwnProperty.call(obj, name)) {
// DO STUFF
}
}
Ответ 3
FYI - пользователи jQuery
jQuery each(callback)
метод использует цикл for( ; ; )
по умолчанию и будет использовать for( in )
, только если длина undefined
.
Поэтому я бы сказал, что безопасно принимать правильный порядок при использовании этой функции.
Пример:
$(['a','b','c']).each(function() {
alert(this);
});
//Outputs "a" then "b" then "c"
Недостатком использования этого является то, что если вы выполняете нелогичную логику, ваши функции будут менее переносимы для других фреймворков. Функция each()
, вероятно, лучше всего зарезервирована для использования с селекторами jQuery, а for( ; ; )
может быть рекомендована в противном случае.
Ответ 4
существуют различия в производительности в зависимости от того, какой цикл вы используете и в каком браузере.
Например:
for (var i = myArray.length-1; i >= 0; i--)
в некоторых браузерах почти в два раза быстрее, чем:
for (var i = 0; i < myArray.length; i++)
Однако, если ваши массивы не являются ОГРОМНЫМИ, или вы постоянно их зацикливаете, все достаточно быстро. Я серьезно сомневаюсь, что цикл цикла является узким местом в вашем проекте (или для любого другого проекта, если на то пошло)
Ответ 5
Обратите внимание, что встроенный метод Array.forEach теперь поддерживается .
Ответ 6
Обновленный ответ на 2012 год текущей версии всех основных браузеров - Chrome, Firefox, IE9, Safari и Opera поддерживают собственный массив ES5.forEach.
Если у вас нет причин поддерживать IE8 изначально (учитывая, что для этих пользователей могут быть предусмотрены ES5-shim или Chrome, что обеспечит надлежащую среду JS), он чище просто использовать соответствующий синтаксис языка:
myArray.forEach(function(item, index) {
console.log(item, index);
});
Полная документация для array.forEach() находится в MDN.
Ответ 7
Второе мнение, что вы должны выбрать метод итерации в соответствии с вашими потребностями. Я бы предположил, что вы действительно не выполняете цикл когда-либо через встроенную структуру Array
с for in
. Это медленнее и, так как Chase Seibert указал на то, что он не был совместим с прототипом.
Отличный критерий для разных стилей циклов, на которые вы абсолютно должны взглянуть, если вы работаете с JavaScript. Не делайте ранних оптимизаций, но вы должны хранить это вещество где-то в задней части головы.
Я бы использовал for in
для получения всех свойств объекта, что особенно полезно при отладке ваших скриптов. Например, мне нравится иметь эту строку, когда я исследую незнакомый объект:
l = ''; for (m in obj) { l += m + ' => ' + obj[m] + '\n' } console.log(l);
Он удаляет содержимое всего объекта (вместе с телами метода) в мой журнал Firebug. Очень.
Ответ 8
Использование forEach для пропуска последовательности прототипов
Просто быстрое дополнение к ответу @nailer выше, использование forEach с Object.keys означает, что вы можете избежать итерации по цепочке прототипов, не используя hasOwnProperty.
var Base = function () {
this.coming = "hey";
};
var Sub = function () {
this.leaving = "bye";
};
Sub.prototype = new Base();
var tst = new Sub();
for (var i in tst) {
console.log(tst.hasOwnProperty(i) + i + tst[i]);
}
Object.keys(tst).forEach(function (val) {
console.log(val + tst[val]);
});
Ответ 9
Эти два значения не совпадают, когда массив разрежен.
var array = [0, 1, 2, , , 5];
for (var k in array) {
// Not guaranteed by the language spec to iterate in order.
alert(k); // Outputs 0, 1, 2, 5.
// Behavior when loop body adds to the array is unclear.
}
for (var i = 0; i < array.length; ++i) {
// Iterates in order.
// i is a number, not a string.
alert(i); // Outputs 0, 1, 2, 3, 4, 5
// Behavior when loop body modifies array is clearer.
}
Ответ 10
вот что я сделал.
function foreach(o, f) {
for(var i = 0; i < o.length; i++) { // simple for loop
f(o[i], i); // execute a function and make the obj, objIndex available
}
}
вот как вы его используете
это будет работать с массивами и объектами (такими как список элементов HTML)
foreach(o, function(obj, i) { // for each obj in o
alert(obj); // obj
alert(i); // obj index
/*
say if you were dealing with an html element may be you have a collection of divs
*/
if(typeof obj == 'object') {
obj.style.marginLeft = '20px';
}
});
Я только что сделал это, поэтому я открыт для предложений:)
Ответ 11
Я бы использовал различные методы, основанные на том, как я хотел бы ссылаться на элементы.
Использовать foreach, если вам нужен только текущий элемент.
Используйте, если вам нужен индекс для выполнения относительных сравнений. (Например, как это соотносится с предыдущим/следующим пунктом?)
Я никогда не замечал разницы в производительности. Я дождался появления проблемы с производительностью, прежде чем беспокоиться об этом.
Ответ 12
С помощью for (var я в myArray) вы можете также перебирать объекты, я буду содержать имя ключа, и вы можете получить доступ к свойству через myArray [i]. Кроме того, любые методы, которые вы добавили в объект, также будут включены в цикл, т.е. Если вы используете какую-либо внешнюю структуру, например jQuery или прототип, или если вы добавляете методы для прототипов объектов напрямую, в какой-то момент я укажу на эти методы.
Ответ 13
Остерегайтесь!
Если у вас несколько тегов script и ваш поиск информации в атрибутах тегов, например, вы должны использовать свойство .length с циклом for, потому что это не простой массив, а объект HTMLCollection.
https://developer.mozilla.org/en/DOM/HTMLCollection
Если вы используете оператор foreach для (var я в вашемList), он вернет proterties и методы HTMLCollection в большинстве браузеров!
var scriptTags = document.getElementsByTagName("script");
for(var i = 0; i < scriptTags.length; i++)
alert(i); // Will print all your elements index (you can get src attribute value using scriptTags[i].attributes[0].value)
for(var i in scriptTags)
alert(i); // Will print "length", "item" and "namedItem" in addition to your elements!
Даже если getElementsByTagName должен вернуть NodeList, большинство браузеров возвращают HTMLCollection:
https://developer.mozilla.org/en/DOM/document.getElementsByTagName
Ответ 14
Для циклов в массивах Массивы не совместимы с Prototype. Если вы считаете, что вам может понадобиться использовать эту библиотеку в будущем, имеет смысл придерживаться циклов.
http://www.prototypejs.org/api/array
Ответ 15
Я видел проблемы с "для каждого" с использованием объектов и прототипов и массивов
Я понимаю, что для каждого есть свойства объектов и массивы NOT
Ответ 16
Если вы действительно хотите ускорить свой код, что с этим связано?
for( var i=0,j=null; j=array[i++]; foo(j) );
это своего рода наличие логики while в инструкции for и она менее избыточна. Также firefox имеет Array.forEach и Array.filter
Ответ 17
Более короткий и лучший код в соответствии с jsperf
keys = Object.keys(obj);
for (var i = keys.length; i--;){
value = obj[keys[i]];// or other action
}
Ответ 18
Используйте цикл Array(). forEach, чтобы воспользоваться parallelism
Ответ 19
for (;;) для Массивы: [20,55,33]
для.. в для объектов: {x: 20, y: 55: z: 33}
Ответ 20
Будьте осторожны!
Я использую Chrome 22.0 в Mac OS, и у меня возникают проблемы с каждым синтаксисом.
Я не знаю, является ли это проблемой браузера, проблемой javascript или некоторой ошибкой в коде, но это ОЧЕНЬ странно. Вне объекта он отлично работает.
var MyTest = {
a:string = "a",
b:string = "b"
};
myfunction = function(dicts) {
for (var dict in dicts) {
alert(dict);
alert(typeof dict); // print 'string' (incorrect)
}
for (var i = 0; i < dicts.length; i++) {
alert(dicts[i]);
alert(typeof dicts[i]); // print 'object' (correct, it must be {abc: "xyz"})
}
};
MyObj = function() {
this.aaa = function() {
myfunction([MyTest]);
};
};
new MyObj().aaa(); // This does not work
myfunction([MyTest]); // This works
Ответ 21
Между ними существует важное различие. Функция in-in выполняет итерацию по свойствам объекта, поэтому, когда случай представляет собой массив, он будет не только перебирать элементы, но также и над функцией "удалить", которую он имеет.
for (var i = 0; i < myArray.length; i++) {
console.log(i)
}
//Output
0
1
for (var i in myArray) {
console.log(i)
}
// Output
0
1
remove
Вы можете использовать for-in с if(myArray.hasOwnProperty(i))
. Тем не менее, при повторении массивов я всегда предпочитаю избегать этого и просто использовать инструкцию for (;;).
Ответ 22
Хотя они оба очень похожи, есть незначительная разница:
var array = ["a", "b", "c"];
array["abc"] = 123;
console.log("Standard for loop:");
for (var index = 0; index < array.length; index++)
{
console.log(" array[" + index + "] = " + array[index]); //Standard for loop
}
в этом случае вывод:
СТАНДАРТ ДЛЯ ЛОП:
ARRAY [0] = A
ARRAY [1] = B
ARRAY [2] = C
console.log("For-in loop:");
for (var key in array)
{
console.log(" array[" + key + "] = " + array[key]); //For-in loop output
}
в то время как в этом случае выход:
FOR-IN LOOP:
ARRAY [1] = B
ARRAY [2] = C
ARRAY [10] = D
ARRAY [ABC] = 123
Ответ 23
Оператор for in позволяет прокручивать имена всех свойств объекта. К сожалению, он также проходит через все элементы, которые были унаследованы через цепочку прототипов. Это имеет плохой побочный эффект от обслуживания функций метода, когда интерес заключается в элементах данных.