Подобный массиву объект в JavaScript

При просмотре dom.js источника из библиотеки Closure я нашел это (в goog.dom.getElementsByTagNameAndClass_):

if (opt_class) {
var arrayLike = {};
var len = 0;
for (var i = 0, el; el = els[i]; i++) {
  var className = el.className;
  // Check if className has a split function since SVG className does not.
  if (typeof className.split == 'function' &&
      goog.array.contains(className.split(' '), opt_class)) {
    arrayLike[len++] = el;
  }
}
arrayLike.length = len;
return arrayLike;
}

Каково было бы преимущество выполнения этого по эквидистантной антенной решетке?

7
задан Maiku Mori 11 January 2010 в 11:31
поделиться

6 ответов

Автор кода использовал пустой объект JavaScript в качестве основы подобного массиву объекта, т.е. такого, к которому можно получить доступ по индексу и который имеет свойство длины.

Могут быть две причины, о которых я мог бы подумать: Использование памяти - если массив поддерживается реализацией, которая выделяет n элементов, то при достижении предела его емкости он увеличивается в какой-то степени и, таким образом, тратит емкость - длину памяти

  • вычислительного времени - реализация выбирает скорость вставки, а не скорость случайного доступа - возврат от этого метода с большей вероятностью будет итерационным, чем от случайного доступа, и изменение размера массива при вставке приводит к выделению копа, которое имеет штраф для вычислительного процессора
  • Готов поспорить, что подобный код будет найден и в других JavaScript библиотеках, и что это результат бенчмаркинга и поиска наиболее подходящего решения в разных браузерах.

    отредактированный после комментария Джастина

    После дальнейшего гугления кажется, что массивоподобные объекты широко распространены среди разработчиков JavaScript: если посмотреть на JavaScript: окончательное руководство Дэвида Флэнагана, в нем есть целый подраздел, посвященный массивоподобным объектам. Также эти ребята упоминают их.

    Никаких упоминаний о том, почему следует отдавать предпочтение массивоподобным объектам по сравнению с массивами. Это может быть хорошим SO вопросом.

    Таким образом, третьим вариантом может быть ключ: соответствие нормам JavaScript API.

    .
    3
    ответ дан 7 December 2019 в 14:33
    поделиться
    goog.dom.getElementsByTagNameAndClass_
    

    Вы имеете дело с коллекциями html. Объект arrayLike - это снэпшот списка узлов, а не объект "живой" коллекции. Он позволяет работать с ним так же просто, как с индексированным массивом, и с меньшей вероятностью вызывает осложнения, если вы создаете или удаляете узлы, проходя через его члены.

    0
    ответ дан 7 December 2019 в 14:33
    поделиться

    В данном случае, на мой взгляд, arrayLike[len++] = el является оптимизацией по сравнению с actualArray.push(el). Однако после выполнения простого бенчмарка (код, приведенный ниже) оказывается, что этот метод на самом деле медленнее, чем использование стандартного массива с помощью метода push, а также с помощью той же самой техники построения.

    Результаты (из OS X 10.5.8, FF 3.5.6) *:

    push construction:        199ms (fastest)
    indexed construction:     209ms
    associative construction: 258ms (slowest)
    

    В заключение, почему Closure в данном случае использует ассоциативный массив, выходит за рамки меня. Скорее всего, на то есть причина (например, эта техника может лучше работать в Chrome, или, что менее сомнительно, эта техника может лучше работать в будущих релизах JavaScript-движков в целом), но я не вижу веской причины в этом случае.

    * Среднее значение не было приведено, так как время варьировалось от тестового прогона к тестовому, но последовательно приводило к одному и тому же порядку. Если вам интересно, то вы можете сделать это самостоятельно.

    * Код бенчмарка:

    var MAX = 100000, i = 0, 
        a1 = {}, a2 = [], a3 = [],
        value = "";
    
    for ( i=0; i<1024; ++i ) {
        value += "a";
    }
    
    console.time("associative construction");
    for ( i=0; i<MAX; ++i ) {
        a1[i] = value;
    }
    a1.length = i;
    console.timeEnd("associative construction");
    
    console.time("push construction");
    for ( i=0; i<MAX; ++i ) {
        a2.push(value);
    }
    console.timeEnd("push construction");
    
    console.time("indexed construction");
    for ( i=0; i<MAX; ++i ) {
        a3[i] = value;
    }
    console.timeEnd("indexed construction");
    

    * Размер и тип значения * несущественны для теста, так как JavaScript использует копирование на запись. Большое (1 кб) значение было использовано для того, чтобы убедить тех читателей, которые не знакомы с этой особенностью JavaScript.

    .
    2
    ответ дан 7 December 2019 в 14:33
    поделиться

    Насколько я знаю, в этом нет никакой пользы, потому что на самом деле нет никакой разницы между этим и "обычным массивом", кроме синтаксиса создания - все объекты Javascript являются ассоциативными массивами.

    .
    -3
    ответ дан 7 December 2019 в 14:33
    поделиться

    не вижу разницы, так как alert(typeof []); возвращает "объект". Всякий раз, когда я вижу что-то подобное (особенно от Goog), я должен предполагать, что это для повышения производительности.

    По сути, это возврат массива без всех унаследованных функций, таких как push и pop.

    .
    0
    ответ дан 7 December 2019 в 14:33
    поделиться

    Я думаю, что в этом примере вместо реального массива создается массивоподобный объект, потому что другие методы DOM также возвращают массивоподобные объекты (NodeList).

    Последовательное использование "массивов-объектов" в API заставляет разработчика избегать использования методов, специфичных для массивов (используя goog.array вместо этого), так что будет меньше попаданий, когда кто-то позже решит изменить вызов getElementsByTagNameAndClass на, скажем, getElementByTagName.

    .
    2
    ответ дан 7 December 2019 в 14:33
    поделиться
    Другие вопросы по тегам:

    Похожие вопросы: