12

我在 Javascript: The Good Parts 上阅读...

由于 JavaScript 的数组实际上是对象,因此该for in语句可用于遍历数组的所有属性。不幸的是,因为 in 不能保证属性的顺序......

据我所知,“每个”函数都基于for in,那么each函数形式的 JQuery 和 Underscore 库在遍历数组时是否保证顺序?我试图避免烦人的标准for

先感谢您。

4

2 回答 2

17

遍历数组时,始终保证顺序。当您遍历(非数组)对象时,就无法保证。顺便说一下,数组仍然是对象。


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;
}
于 2012-05-24T15:05:58.427 回答
3

有两种方法可以遍历数组:对数组的索引元素进行数值循环,或者对数组的对象属性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,因为这是定义属性的顺序(但也不能保证您的浏览器甚至需要表现出这种行为)。

到目前为止,数值循环看起来更好,但它们不能处理备用数组,即有间隙的数组。ES5Array.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索引顺序返回您的值,但forEachUnderscore 对于稀疏数组似乎更胜一筹,因为它们忽略了尚未分配给它们的值的索引。

于 2012-05-24T15:51:20.340 回答