Bezdepbonusu7Программирование: статьи и ответы

Вопрос

JQuery $.each() возится, если объект, отличный от массива, имеет свойство длины

Автор вопроса: ChristopherОтветов: 2

Я работаю над очень, очень, очень простой библиотекой, чтобы предоставить некоторые удобные функции для работы с собственными объектами 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, у которого есть имя свойства "длина", каждый () взорвется, как недееспособный феникс. Это может произойти, если я рекурсивно работаю с большим объектом, определяющим элементы DOM, которые могут включать свойство длины, предназначенное для указания длины отображения символов в пользовательском интерфейсе. Значение 200 здесь катастрофично: внезапно каждый() повторяет 0-199 по значению реквизита.

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

javascriptarraysjqueryeach

Ответы

Ответ 1 · рейтинг 3 · jfriend00

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

Если у вас есть объект со свойством .length и вещи, которые вы хотите перебрать, не являются числовыми индексами от 0 до length-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;
},

Ответ 2 · dstarh

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

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы