Самый быстрый способ конвертировать JavaScript NodeList в Array?

ранее ответил на вопросы здесь сказал, что это был самый быстрый способ:

//nl is a NodeList
var arr = Array.prototype.slice.call(nl);

в бенчмаркинге в моем браузере я обнаружил, что он более чем в 3 раза медленнее, чем это:

var arr = [];
for(var i = 0, n; n = nl[i]; ++i) arr.push(n);

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

это причуда в моем браузере (Chromium 6)? Или есть быстрее способ?

EDIT: для всех, кто заботится, я остановился на следующем (который, кажется, самый быстрый в каждом браузере, который я тестировал):

//nl is a NodeList
var l = []; // Will hold the array of Node's
for(var i = 0, ll = nl.length; i != ll; l.push(nl[i++]));

EDIT2: я нашел еще более быстрый способ

// nl is the nodelist
var arr = [];
for(var i = nl.length; i--; arr.unshift(nl[i]));

13 ответов


второй, как правило, быстрее в некоторых браузерах, но главное, что вы должны использовать его, потому что первый просто не кросс-браузер. Хотя времена меняются!--2-->

@kangax (IE 9 предварительный просмотр)

массив.прототип.ломтик теперь можно конвертировать некоторые объекты хоста (например, NodeList) к массивам-то, что большинство современные браузеры были уметь делать довольно долго.

пример:

Array.prototype.slice.call(document.childNodes);

С ES6 теперь у нас есть простой способ создать массив из списка узлов:Array.from()


вот новый классный способ сделать это с помощью ES6 оператор распространения:

let arr = [...nl];

некоторые оптимизации:

  • сохранить длину NodeList в переменной
  • явно задать длину массива перед установкой.
  • доступ к индексам, а не подталкивание или ... непоколебимой.

код (см. Этот тест jsperf):

var arr = [];
for (var i = 0, ref = arr.length = nl.length; i < ref; i++) {
 arr[i] = nl[i];
}

результат будет полностью зависеть от браузера, чтобы дать объективный вердикт, мы должны сделать некоторые тесты, вот результаты, вы можете запустить их здесь:

Chrome 6:

Firefox 3.6:

Firefox 4.0b2:

Safari 5:

платформа ИЕ9 просмотра 3:


самый быстрый и кросс-браузер

for(var i=-1,l=nl.length;++i!==l;arr[i]=nl[i]);

Как я сравнивал в

http://jsbin.com/oqeda/98/edit

* спасибо @CMS за идею!

Chromium (Similar to Google Chrome)FirefoxOpera


NodeList.prototype.forEach = Array.prototype.forEach;

теперь вы можете сделать документ.querySelectorAll ('div').forEach (функция ()...)


быстрее и короче :

// nl is the nodelist
var a=[], l=nl.length>>>0;
for( ; l--; a[l]=nl[l] );

проверить это сообщение в блоге здесь это говорит об одном и том же. Насколько я понимаю, дополнительное время может быть связано с продвижением по цепочке прицела.


Это функция, которую я использую в своем JS:

function toArray(nl) {
    for(var a=[], l=nl.length; l--; a[l]=nl[l]);
    return a;
}

вот диаграммы, обновленные на дату этой публикации (диаграмма "неизвестная платформа" - Internet Explorer 11.15.16299.0):

Safari 11.1.2Firefox 61.0Chrome 68.0.3440.75Internet Explorer 11.15.16299.0

из этих результатов кажется, что метод preallocate 1 является самой безопасной кросс-браузерной ставкой.


просто быть завершителем здесь, и это быстро тип:

let arr1 = Array.prototype.filter.call(nl, n => true);

let arr2 = Array.prototype.map.call(nl, n => n);

простой способ преобразовать массив-как объекты в массив

nodeList = Array.from(document.querySelectorAll('li'))
// Checking if it's array
Array.isArray(nodeList) // true