jQuery $ .each () суетится, если не-массив объект имеет свойство длины - PullRequest
2 голосов
/ 09 сентября 2011

Я работаю над очень, очень, очень простой библиотекой , чтобы обеспечить некоторые удобные функции для работы с нативными объектами JavaScript, в идеале (в конечном итоге) в стиле jQuery.

У меня очень простая функция: crawlObject, которую я изменил, чтобы использовать each() в jQuery вместо цикла 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, так и "plain"«Объекты JS без дополнительной логики.

Но.

Если я передаю «простой» объект JS, у которого, как оказалось, есть имя свойства «length», каждый () взрывается как нефункциональный феникс.Это может произойти, если я возвращаюсь к большому объекту, определяющему элементы DOM, который может включать свойство длины, предназначенное для указания длины отображения символа в пользовательском интерфейсе.Значение 200 здесь является катастрофическим: внезапно каждый () выполняет итерацию 0-199 для значения реквизита.

Прежде чем я инвестирую в какой-либо дальнейший рефакторинг, кто-нибудь сталкивался с решением этой проблемы?

Ответы [ 2 ]

3 голосов
/ 09 сентября 2011

Документация jQuery для jQuery.each () четко заявляет, что если объект имеет свойство .length, то он выполняет итерацию по числовому индексу от 0 до длины-1 (как и следовало ожидать для массива или массивоподобный объект).

Если у вас есть объект со свойством .length и вещи, которые вы хотите перебрать, не являются числовыми индексами от 0 до длины-1, то jQuery.each() не будет делать то, что вы хотите, и вы не должны его использовать.

Вот специальный код для jQuery.each() из источника jQuery. Во 2-й и 3-й строках функции вы можете видеть, что если есть object.length, isObj будет 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;
},
0 голосов
/ 09 сентября 2011

Я думаю, что если (thisObj.hasOwnProperty ("length")) может сделать это для вас

...