如果非Array对象具有length属性,则jQuery $ .each()会发生错误

时间:2011-09-09 03:26:36

标签: javascript jquery arrays each

我正在研究very, very, very simple library以提供一些便利功能来处理本机JavaScript对象,理想情况下(最终)以类似jQuery的方式。

我有一个简单的函数:crawlObject我修改为使用jQuery的each()而不是for(var key in obj)循环。

function crawlObject(thisObj, onSuccess, doRecursion) {
    var stopCrawling = false;
    if (isFunction(onSuccess) && ($.isPlainObject(thisObj) || isArray(thisObj))) {
        $.each(thisObj, function(childKey, value) {
            var childObj = thisObj[childKey];
            if (false === stopCrawling) {
                stopCrawling = isTrue(onSuccess(childObj, childKey, thisObj, value));
            }
            if (false === stopCrawling && doRecursion) {
                stopCrawling = isTrue(crawlObject(childObj, onSuccess, doRecursion));
            }
        });
    }
    return stopCrawling;
}

这具有爬行Array对象和“普通”JS对象而无需额外逻辑的优点。

但是

如果我传递的“普通”JS对象碰巧有一个属性名称为'length',则每个()内爆就像一个功能失调的凤凰。如果我在定义DOM元素的大对象上进行递归,则可能会发生这种情况,DOM元素可能包含用于指示UI中字符显示长度的length属性。这里的值为200是灾难性的:突然每个()在道具的值上迭代0-199。

在我投资任何进一步的重构之前,有没有人偶然找到解决这个问题的方法?

2 个答案:

答案 0 :(得分:3)

jQuery的documentation for jQuery.each()清楚地指出,如果对象具有.length属性,那么它将从0到长度为1的数字索引进行迭代(就像您对数组或类数组对象所期望的那样) 。

如果你有一个.length属性的对象,你要迭代的东西不是从0到长度为1的数字索引,那么jQuery.each()将不会做你想要的,你不应该使用它。

以下是jQuery源代码中jQuery.each()的具体代码。您可以在函数的第2行和第3行看到,如果有object.lengthisObj将是false,并且以后它不会被视为对象:

// args is for internal usage only
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;
},

答案 1 :(得分:0)

我认为如果(thisObj.hasOwnProperty(“length”))可能会为你做这件事