JQuery и Underscore "каждый" гарантируют порядок для массива?

Я читал на Javascript: Хорошие детали...

Поскольку массивы JavaScripts - действительно объекты, оператор for in может использоваться для перебора всех свойств массива. К сожалению, поскольку in не дает никаких гарантий относительно порядка свойств...

Насколько я знаю, "каждая" функция основана на for in, тогда функция формы each формирует библиотеки JQuery и Underscore, гарантируя порядок при их переходе по массиву? Я пытаюсь избежать раздражающего стандарта for.

Спасибо заранее.

Ответ 1

При повторении массива всегда гарантируется порядок. Это когда вы перебираете объекты (не массивы), когда нет гарантии. Массивы по-прежнему остаются объектами.


each - это не более чем for in для объектов, а for для типа массива. структура определяет правильный цикл для задания и применяется одна и та же логика: Итерации массивов упорядочены, а итерация объектов - нет.

Источник подчеркивания:

var each = _.each = _.forEach = function (obj, iterator, context) {
        if (obj == null) return;
        if (nativeForEach && obj.forEach === nativeForEach) {
            obj.forEach(iterator, context);
        } else if (obj.length === +obj.length) {
            for (var i = 0, l = obj.length; i < l; i++) {
                if (i in obj && iterator.call(context, obj[i], i, obj) === breaker) return;
            }
        } else {
            for (var key in obj) {
                if (_.has(obj, key)) {
                    if (iterator.call(context, obj[key], key, obj) === breaker) return;
                }
            }
        }
    };

Источник jQuery:

each: function (object, callback, args) {
    var name, i = 0,
        length = object.length,
        isObj = length === undefined || jQuery.isFunction(object);
    if (args) {
        if (isObj) {
            for (name in object) {
                if (callback.apply(object[name], args) === false) {
                    break;
                }
            }
        } else {
            for (; i < length;) {
                if (callback.apply(object[i++], args) === false) {
                    break;
                }
            }
        }
        // A special, fast, case for the most common use of each
    } else {
        if (isObj) {
            for (name in object) {
                if (callback.call(object[name], name, object[name]) === false) {
                    break;
                }
            }
        } else {
            for (; i < length;) {
                if (callback.call(object[i], i, object[i++]) === false) {
                    break;
                }
            }
        }
    }
    return object;
}

Ответ 2

Есть два пути, по которым вы можете перебирать массив: числовой цикл над индексированными элементами массива или цикл for in над свойствами объекта массива.

var a = ['a','b'];
a[3] = 'e';
a[2] = 'd';
a.foo = function() { };
for(key in a)
    console.log(key);

Это возвращает 0 1 3 2 foo, так как это порядок, в котором были определены свойства (но нет никаких обещаний, которые ваш браузер даже должен проявлять это поведение).

Пока численные циклы выглядят превосходно, но они не могут обрабатывать запасные массивы, т.е. массивы с пробелами. ES5 Array.forEach опускает неопределенные значения, а jQuery $.each использует числовой цикл, основанный на свойстве length.

var a = [1,2];
a[1000000] = 4;
a[9000] = 3;
a.foo = function() {};

// outputs 0, 1, 9000, 1000000 -- note they are in order
a.forEach(function(elem, index){ console.log(index); })

// outputs 0, 1, 9000, 1000000 -- same as above
_.each(a, function(elem, index){ console.log(index); }) 

// outputs a million values and locks up  your browser for a while
$.each(a, function(index){ console.log(index); })

Итак, как forEach, так и $.each возвращают ваши значения в порядке индекса, но forEach и Underscore кажутся выше для разреженных массивов, поскольку они игнорируют индексы, у которых не было назначенного им значения.