Spiegazione di [] .slice.call in javascript?


197

Mi sono imbattuto in questa scorciatoia per convertire un Elenco nodi DOM in un array normale, ma devo ammettere che non capisco completamente come funziona:

[].slice.call(document.querySelectorAll('a'), 0)

Quindi inizia con un array vuoto [], quindi sliceviene utilizzato per convertire il risultato callin un nuovo array, vero?

Il po 'che non capisco è il call. Come viene convertito document.querySelectorAll('a')da un NodeList a un array normale?


5
Array.prototype.slice.call(document.querySelectorAll('a'));è un modo corretto di scrivere il pezzo di codice che hai scritto.
vdegenne,

4
A proposito, il metodo ES6 moderno (e intuitivamente comprensibile) è lo stesso Array.from. Quindi, ad esempio, questo farebbe lo stesso: Array.from (document.querySelectorAll ('a'));
rugk,

Risposte:


158

Quello che sta succedendo qui è che chiami slice()come se fosse una funzione NodeListdell'uso call(). Ciò che slice()fa in questo caso è creare un array vuoto, quindi scorrere attraverso l'oggetto su cui è in esecuzione (originariamente un array, ora a NodeList) e continuare ad aggiungere gli elementi di tale oggetto all'array vuoto che ha creato, che alla fine viene restituito. Ecco un articolo su questo .

MODIFICARE:

Quindi inizia con un array vuoto [], quindi lo slice viene utilizzato per convertire il risultato della chiamata in un nuovo array, vero?

Non è giusto. [].slicerestituisce un oggetto funzione. Un oggetto funzione ha una funzione call()che chiama la funzione assegnando il primo parametro di call()a this; in altre parole, facendo pensare alla funzione che viene chiamata dal parametro ( NodeListrestituito da document.querySelectorAll('a')) piuttosto che da un array.


59
Si noti anche qui che sebbene ciò sia semanticamente equivalente a dire Array.prototype.slice.call(...), in realtà crea un'istanza di un oggetto array ( []) solo per accedere al suo metodo di slice prototipo. Questa è un'istanza sprecata. Dire Array.prototype.slice.call(...)invece è più pulito, anche se aggiungi diversi personaggi al tuo JS se stai contando ...
Ben Zotto

Si noti che funziona in IE 8 e versioni successive solo su oggetti Array, quindi non sarà possibile clonare NodeLists
Livingston Samuel

5
@quixoto []è più affidabile poiché Arraypotrebbe essere sovrascritto in qualcos'altro. Se devi riutilizzarlo Array#slice, è una buona idea memorizzarlo nella cache.
Mathias Bynens,

2
Nel caso in cui qualcun altro stia cercando un modo per farlo in IE8, dai un'occhiata a questa domanda stackoverflow.com/questions/3199588/…
Liam Newmarch

1
In realtà ho visto questo schema apparire nel codice sorgente backbone.js: var array = []; var push = array.push; var slice = array.slice; var splice = array.splice;lo fa per il problema di sicurezza menzionato da @MathiasBynens?
owensmartin,

125

In JavaScript, i metodi di un oggetto possono essere associati a un altro oggetto in fase di esecuzione. In breve, JavaScript consente a un oggetto di "prendere in prestito" il metodo di un altro oggetto:

object1 = {
    name: 'Frank',
    greet() {
        alert(`Hello ${this.name}`);
    }
};

object2 = {
    name: 'Andy'
};

// Note that object2 has no greet method,
// but we may "borrow" from object1:

object1.greet.call(object2); // Will show an alert with 'Hello Andy'

I metodi calle applydegli oggetti funzione (in JavaScript, anche le funzioni sono oggetti) ti permettono di farlo. Quindi, nel tuo codice potresti dire che il NodeList sta prendendo in prestito il metodo slice di un array. .slice()restituisce un altro array come risultato, che diventerà l'array "convertito" che sarà quindi possibile utilizzare.


Bang on 🎯 spiegazione del concetto astratto per le funzioni dell'oggetto javascript. Ora, puoi applicarlo per la callfunzione di Array.prototypeaka [].prototypete stesso.
Sourabh,

29

Recupera la slicefunzione da un Array. Quindi chiama quella funzione, ma utilizzando il risultato di document.querySelectorAllcome thisoggetto anziché un array reale.


19

È una tecnica per convertire oggetti simili a array in array reali.

Alcuni di questi oggetti includono:

  • arguments nelle funzioni
  • NodeList (ricorda che il loro contenuto può cambiare dopo essere stato recuperato! Quindi convertirli in array è un modo per congelarli)
  • Collezioni jQuery, alias oggetti jQuery (alcuni documenti: API , tipo , apprendimento )

Questo serve a molti scopi, ad esempio gli oggetti vengono passati per riferimento mentre gli array vengono passati per valore.

Inoltre, nota che il primo argomento 0può essere omesso, spiegazione approfondita qui .

E per completezza, c'è anche jQuery.makeArray () .


15

Come si converte document.querySelectorAll('a')da un NodeList array normale?

Questo è il codice che abbiamo,

[].slice.call(document.querySelectorAll('a'), 0)

Lascialo prima smantellare,

  []    // Array object
.slice // Accessing the function 'slice' present in the prototype of Array
.call // Accessing the function 'call' present in the prototype of function object(slice)
(document.querySelectorAll('a'),0) 
    // 'call' can have arguments like, (thisArg, arg1,arg2...n). 
   // So here we are passing the 'thisArg' as an array like object,
  // that is a 'nodeList'. It will be served as 'this' object inside of slice function.
 // And finally setting 'start' argument of slice as '0' and leaving the 'end' 
// argument as 'undefined'

Step: 1 Esecuzione della callfunzione

  • All'interno call, oltre a thisArg, il resto degli argomenti verrà aggiunto a un elenco di argomenti.
  • Ora la funzione sliceverrà invocata legando il suo thisvalore come thisArg(oggetto come array come document.querySelector) e con l'elenco degli argomenti. cioè] argomento startche contiene0

Passaggio: 2 Esecuzione della slicefunzione richiamata all'interno dicall

  • startverrà assegnato a una variabile scome0
  • poiché endè undefined, this.lengthsarà memorizzato ine
  • un array vuoto verrà archiviato in una variabile a
  • Dopo aver effettuato le impostazioni di cui sopra, si verificherà la seguente iterazione

    while(s < e) {
      a.push(this[s]);
      s++;
    }
  • l'array riempito averrà restituito come risultato.

PS Per una migliore comprensione del nostro scenario alcuni passaggi necessari per il nostro contesto sono stati ignorati dall'algoritmo originale di call e slice .


1
Spiegazione gradevolissima. Eccezionale! Grazie :)
kittu,

1
Bella spiegazione.
NaveenDA,

7
[].slice.call(document.querySelectorAll('.slide'));

1. The querySelectorAll() method returns all elements in the document that matches a specified selector(s). 

2. The call() method calls a function with a given this value and arguments provided individually.

3. The slice() method returns the selected elements in an array, as a new array object.

  so this line return the array of [object HTMLDivElement]. Here is the six div with classname "slide" so array length will be 6.

<div class="slideshow">

  <div class="slide">
    first slider1
  </div>
  <div class="slide">
    first slider2
  </div>
  <div class="slide">
    first slider3
  </div>
  <div class="slide">
    first slider4
  </div>
  <div class="slide">
    first slider5
  </div>
  <div class="slide">
    first slider6
  </div>

</div>

<script type="text/javascript">

  var arraylist = [].slice.call(document.querySelectorAll('.slide'));

  alert(arraylist);

</script>

4

Da ES6: crea semplicemente un array con Array.from (element.children) o Array.from ({lunghezza: 5})

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.