2010-01-24 20 views
140

mi sono imbattuto su questo collegamento pulito per la conversione di un DOM NodeList in una serie regolare, ma devo ammettere, non del tutto a capire come funziona:Spiegazione di [] .slice.call in javascript?

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

Così si comincia con un array vuoto [], poi slice viene utilizzato per convertire il risultato di call in un nuovo array sì?

Il bit che non capisco è lo call. In che modo converte document.querySelectorAll('a') da un NodeList a un array normale?

+2

'Array.prototype.slice.call (documento .querySelectorAll ('a')); 'è un modo corretto di scrivere il pezzo di codice che hai scritto. – user544262772

risposta

112

Quello che sta accadendo qui è che si chiama slice() come se fosse una funzione di NodeList utilizzando call(). Quello che slice() fa in questo caso è creare un array vuoto, quindi scorrere l'oggetto su cui è in esecuzione (in origine un array, ora un NodeList) e continuare ad aggiungere gli elementi di quell'oggetto all'array vuoto creato, che viene infine restituito. Ecco uno article on this.

EDIT:

Così inizia con un array vuoto [], quindi la fetta viene utilizzato per convertire il risultato di chiamata a un nuovo array sì?

Non è giusto. [].slice restituisce un oggetto funzione. Un oggetto funzione ha una funzione call() che chiama la funzione che assegna il primo parametro di call() a this; in altre parole, facendo in modo che la funzione pensi di essere chiamata dal parametro (lo NodeList restituito da document.querySelectorAll('a')) anziché da un array.

+40

Nota anche qui che sebbene questo 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 è una istanziazione sprecata. Dire "Array.prototype.slice.call (...)" invece è più pulito, anche se aggiungi diversi caratteri al tuo JS se stai contando ... –

+0

Nota che questo funziona in IE 8 e sotto solo sugli oggetti Array, quindi non sarà possibile clonare 'NodeList's –

+5

@quixoto' [] 'è più affidabile poiché' Array' potrebbe essere sovrascritto su qualcos'altro. Se hai bisogno di riutilizzare 'Array # slice ', è una buona idea metterlo nella cache. –

22

Recupera la funzione slice da un Array. Quindi chiama tale funzione, ma utilizza il risultato di document.querySelectorAll come oggetto this anziché un array effettivo.

88

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

object1 = { 
    name:'frank', 
    greet:function(){ 
     alert('hello '+this.name) 
    } 
}; 

object2 = { 
    name:'andy' 
}; 

// Note that object2 has no greet method. 
// But we may "borrow" from object1: 

object1.greet.call(object2); 

I call e apply metodi di oggetti funzionali (in JavaScript funzioni sono oggetti così) permette di fare questo. Quindi nel tuo codice potresti dire che Nodelist sta prendendo in prestito il metodo slice di una matrice. Che cosa è la conversione è il fatto che slice restituisce un altro array come risultato.

+4

plus 1 v. buona realizzazione dell'idea generica dietro questa – Dexters

17

È una tecnica per convertire oggetti di tipo array in array reali.

Alcuni di questi oggetti sono:

  • arguments nelle funzioni
  • (ricordate il loro contenuto può cambiare dopo essere inverosimile!così convertendoli in array è un modo di congelarli)
  • collezioni jQuery, alias oggetti jQuery (alcuni doc: API, type, learn)

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

Inoltre, si noti che il primo argomento 0 può essere omesso, thorough explanation here.

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

8

Come che converte document.querySelectorAll('a') da un NodeList ad una serie regolare?

Questo è il codice che abbiamo,

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

Lets smontarlo prima,

[] // 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' 

Fase: 1 Esecuzione di call funzione

  • All'interno call, altro rispetto allo thisArg, il il resto degli argomenti verrà aggiunto a un elenco di argomenti.
  • Ora la funzione slice sarà richiamato legando il suo valore come this thisArg (array come oggetto venuto dal document.querySelector) e con la lista degli argomenti. cioè] argomento start che contiene 0

Fase: 2 Esecuzione di slice funzione chiamata all'interno di call

  • start verrà assegnato ad una variabile s come 0
  • dal end è undefined, this.length sarà essere memorizzato in e
  • un vuoto a RRay saranno memorizzati in una variabile a
  • Dopo aver effettuato le impostazioni sopra il seguente iterazione sarà accaduto

    while(s < e) { 
        a.push(this[s]); 
        s++; 
    } 
    
  • matrice riempito a verrà restituito come risultato.

P.S Per una migliore comprensione del nostro scenario alcuni passi che sono necessari per il nostro contesto è stato ignorato dalla algoritmo proprietario di call e slice.

+1

spiegazione passo passo molto bella. Eccezionale! Grazie :) – Satyadev

+1

Bella spiegazione. – NaveenDA

1
[].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> 
0

Da ES6: Basta fare array con Array.from (element.children) o Array.from ({lunghezza: 5})