JavaScript для... в сравнении с
Как вы думаете, есть большая разница в циклах for... in и for? Какое "для" вы предпочитаете использовать и почему?
Допустим, у нас есть массив ассоциативных массивов:
var myArray = [{'key': 'value'}, {'key': 'value1'}];
Итак, мы можем повторить:
for (var i = 0; i < myArray.length; i++)
А также:
for (var i in myArray)
Я не вижу большой разницы. Есть ли проблемы с производительностью?
24 ответа
Выбор должен быть основан на том, какая идиома лучше всего понимается.
Массив повторяется с использованием:
for (var i = 0; i < a.length; i++)
//do stuff with a[i]
Объект, используемый в качестве ассоциативного массива, повторяется с использованием:
for (var key in o)
//do stuff with o[key]
Если у вас нет причин разрушить землю, придерживайтесь установленной схемы использования.
Дуглас Крокфорд рекомендует в JavaScript: Хорошие детали (стр. 24) избегать использования for in
заявление.
Если вы используете for in
Чтобы зациклить имена свойств в объекте, результаты не упорядочены. Хуже: вы можете получить неожиданные результаты; в него входят члены, унаследованные от цепочки прототипов, и имена методов.
Все, кроме свойств, может быть отфильтровано .hasOwnProperty
, Этот пример кода делает то, что вы, вероятно, хотели изначально:
for (var name in obj) {
if (Object.prototype.hasOwnProperty.call(obj, name)) {
// DO STUFF
}
}
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( ; ; )
может быть целесообразно в противном случае.
Существуют различия в производительности в зависимости от того, какой цикл вы используете и в каком браузере.
Например:
for (var i = myArray.length-1; i >= 0; i--)
почти в два раза быстрее в некоторых браузерах, чем:
for (var i = 0; i < myArray.length; i++)
Однако, если ваши массивы ОГРОМНЫ или вы не зацикливаете их постоянно, все достаточно быстро. Я серьезно сомневаюсь, что зацикливание массивов является узким местом в вашем проекте (или для любого другого проекта в этом отношении)
Обратите внимание, что родной метод Array.forEach теперь широко поддерживается.
Обновленный ответ для текущей версии всех основных браузеров 2012 года - Chrome, Firefox, IE9, Safari и Opera поддерживают встроенный массив ES5. ForEach.
Если у вас нет причин поддерживать нативную поддержку IE8 (имея в виду, что этим пользователям могут быть предоставлены рамки ES5-shim или Chrome, что обеспечит надлежащую среду JS), проще использовать правильный синтаксис языка:
myArray.forEach(function(item, index) {
console.log(item, index);
});
Использование 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]);
});
Два не совпадают, когда массив разреженный.
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.
}
Я полагаю, что вы должны выбрать метод итерации в соответствии с вашими потребностями. Я бы посоветовал вам вообще не зацикливаться на родном Array
с for in
состав. Это намного медленнее и, как указывал Чейз Сейберт в тот момент, не совместимо с платформой Prototype.
Существует отличный эталон для различных стилей зацикливания, на которые вам обязательно следует обратить внимание, если вы работаете с JavaScript. Не делайте ранних оптимизаций, но вы должны держать эти вещи где-то в затылке.
я хотел бы использовать for in
получить все свойства объекта, что особенно полезно при отладке ваших скриптов. Например, мне нравится иметь эту строку под рукой, когда я исследую незнакомый объект:
l = ''; for (m in obj) { l += m + ' => ' + obj[m] + '\n' } console.log(l);
Он выгружает содержимое всего объекта (вместе с телами методов) в мой журнал Firebug. Очень удобно
Вот что я сделал
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';
}
});
Я просто сделал это, поэтому я открыт для предложений:)
Я бы использовал разные методы, основанные на том, как я хотел ссылаться на элементы.
Используйте foreach, если вы просто хотите текущий элемент.
Используйте для, если вам нужен индексатор для сравнительных сравнений. (Т.е. как это соотносится с предыдущим / следующим пунктом?)
Я никогда не замечал разницу в производительности. Я подожду, пока возникнут проблемы с производительностью, прежде чем беспокоиться об этом.
Осторожно!
Если у вас есть несколько тегов сценария, и вы ищете информацию в атрибутах тега, например, вы должны использовать свойство.length с циклом for, потому что это не простой массив, а объект HTMLCollection.
https://developer.mozilla.org/en/DOM/HTMLCollection
Если вы используете оператор foreach для (var i в yourList), он вернет свойства и методы 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
С помощью for (var i в myArray) вы также можете перебирать объекты, я буду содержать имя ключа и вы можете получить доступ к свойству через myArray [i]. Кроме того, любые методы, которые вы добавите к объекту, будут также включены в цикл, т. Е. Если вы используете какую-либо внешнюю среду, такую как jQuery или prototype, или если вы добавляете методы непосредственно к прототипам объектов, в какой-то момент я укажу на эти методы.
Я видел проблемы с "для каждого" с использованием объектов и прототипов и массивов
я понимаю, что для каждого для свойств объектов, а не массивов
Более короткий и лучший код в соответствии с jsperf
keys = Object.keys(obj);
for (var i = keys.length; i--;){
value = obj[keys[i]];// or other action
}
Ибо в циклах на массивах не совместим с прототипом. Если вы думаете, что вам может понадобиться использовать эту библиотеку в будущем, имеет смысл придерживаться циклов for.
Если вы действительно хотите ускорить свой код, что на счет этого?
for( var i=0,j=null; j=array[i++]; foo(j) );
это своего рода наличие логики while в операторе for, и она менее избыточна. Также Firefox имеет Array.forEach и Array.filter
для (;;) для массивов: [20,55,33]
for..in для объектов: {x:20,y:55:z:33}
Используйте цикл Array(). ForEach, чтобы использовать преимущества параллелизма.
Хотя они оба очень похожи, есть небольшая разница:
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
}
в то время как в этом случае вывод:
ВНЕШНЯЯ ПЕТЛЯ
ARRAY [1] = B
ARRAY [2] = C
ARRAY [10] = D
ARRAY [ABC] = 123
Оператор for позволяет циклически проходить по именам всех свойств объекта. К сожалению, он также проходит по всем элементам, унаследованным через цепочку прототипов. У этого есть плохой побочный эффект обслуживания функций метода, когда интерес к членам данных.
Быть осторожен!!! Я использую 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
Используйте for in для перебора объекта. Он имеет более короткий синтаксис и прост в использовании. Здесь слово происходит от index. Рассматривайте свойства объекта как индекс и перебирайте его. Если вы используете for in для массива, вы получите индекс элементов, присутствующих внутри массива.
Между ними есть важное различие. For-in перебирает свойства объекта, поэтому, когда case является массивом, он будет перебирать не только свои элементы, но и функцию "удалить", которая у него есть.
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(;;).