Maneira mais rápida de converter JavaScript NodeList para Array?

Anteriormente respondeu perguntas aqui disse que este foi o caminho mais rápido:

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

Em benchmarking no meu navegador eu descobri que é mais de 3 vezes mais lento que isso:

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

Ambos produzem a mesma saída, mas acho difícil acreditar que minha segunda versão seja a mais rápida possível, especialmente porque as pessoas disseram o contrário aqui.

Isso é um capricho no meu navegador (Chromium 6)? Ou há um caminho mais rápido?

EDIT: Para quem se importa, eu decidi o seguinte (que parece ser o mais rápido em cada navegador que eu testei):

 //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: Eu encontrei um caminho ainda mais rápido

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

    O segundo tende a ser mais rápido em alguns navegadores, mas o ponto principal é que você tem que usá-lo porque o primeiro não é apenas cross-browser. Mesmo que The Times eles estão mudando

    @kangax ( visualização do IE 9 )

    O Array.prototype.slice agora pode converter determinados objects de host (por exemplo, NodeList) em matrizes – algo que a maioria dos navegadores modernos conseguiu fazer por um bom tempo.

    Exemplo:

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

    Com o ES6, agora temos uma maneira simples de criar um Array a partir de uma NodeList: a function Array.from() .

     // nl is a NodeList let myArray = Array.from(nl) 

    Aqui está uma nova maneira legal de fazer isso usando o operador de spread do ES6 :

     let arr = [...nl]; 

    Algumas otimizações:

    • salve o comprimento do NodeList em uma variável
    • defina explicitamente o comprimento da nova matriz antes de definir.
    • acessar os índices, em vez de empurrar ou desviar.

    Código ( jsPerf ):

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

    Os resultados vão depender completamente do navegador, para dar um veredicto objective, temos que fazer alguns testes de performance, aqui estão alguns resultados, você pode executá-los aqui :

    Chrome 6:

    Firefox 3.6:

    Firefox 4.0b2:

    Safari 5:

    Pré-visualização da plataforma IE9 3:

    O navegador mais rápido e cruzado é

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

    Como eu comparei

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

    * Obrigado @CMS pela ideia!

    Chromium (semelhante ao Google Chrome)Raposa de fogoÓpera

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

    Agora você pode document.querySelectorAll (‘div’). ForEach (function () …)

    mais rápido e mais curto:

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

    Confira este post aqui que fala sobre a mesma coisa. Pelo que eu sei, o tempo extra pode ter a ver com subir a cadeia de escopo.

    Esta é a function que eu uso no meu JS:

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

    Apenas sendo um completista aqui, e estes são rápidos para digitar:

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

    Aqui estão os charts atualizados a partir da data desta postagem (o gráfico “plataforma desconhecida” é o Internet Explorer 11.15.16299.0):

    Safari 11.1.2Firefox 61.0Chrome 68.0.3440.75Internet Explorer 11.15.16299.0

    A partir desses resultados, parece que o método de pré-locação 1 é a aposta cross-browser mais segura.