2012-06-07 19 views
9

Ho visto questo script da qualche altra parte, e sarà controllare ogni singolo caselle di controllo:"[] .forEach"

[].forEach.call(document.querySelectorAll('input[type="checkbox"]'),function(el){ 
     el.checked=true; 
    } 
);​ 

so come usare forEach:

[0,1,2].forEach(function(num){ 
    console.log(num); 
}); 

//0 
//1 
//2 

Ma ora , è [].forEach e non c'è niente dentro. Quindi perché funziona ancora? Perché non posso farlo invece?

document.querySelectorAll('input[type="checkbox"]').forEach(function(el){ 
     el.checked=true; 
    } 
);​ 
+0

È possibile. Il primo finisce per essere lo stesso attraverso il riflesso. Controlla 'call'and' apply'. – entonio

+2

Si noti che questa tecnica '[] .forEach.call (nodeList, fn)' non funziona in IE8 **, quindi non è possibile utilizzarlo in circostanze generali. –

+1

È possibile * tecnicamente * aggiungere il metodo per utilizzarlo su un risultato di 'querySelectorAll', ma è una strada irta di pericoli. 'NodeList.prototype.forEach = HTMLCollection.prototype.forEach = Array.prototype.forEach;' –

risposta

10

JavaScript ha funzioni di prima classe; cioè, sono trattati come oggetti e possono avere le loro proprietà e metodi. Il metodo incorporato Function.call accetta un parametro this per la funzione come primo argomento e il resto degli argomenti viene passato alla funzione stessa. L'array [] non viene utilizzato, tranne che come mezzo per accedere al metodo (meno conciso, quindi meno utilizzato) Array.prototype.forEach.

Si tratta fondamentalmente di una riconnessione di Array.forEach per l'utilizzo su qualcosa che non è un array, in questo caso uno NodeList. Se NodeList s offerto un metodo forEach, allora sarebbe equivalente a, e si può leggere come, in questo modo:

document.querySelectorAll('input[type="checkbox"]').forEach(function(el) { 
    el.checked = true; 
});​ 

Così, un po 'più in profondità. call eseguirà una funzione con un contesto diverso. forEach itera sul contesto e chiama la funzione passata come argomento. Quindi un someFunc.call(thisArg, otherArg) verrà eseguito come se fosse nel contesto di thisArg, come thisArg.someFunc(otherArg). Ecco l'esempio più semplice:

function callMe(something) { 
    return something + this; 
} 

callMe('Hello'); // Hellonull or Hello[object Window] or something 
callMe.call({}, 'World'); // World[object Object] 

apply() funziona allo stesso modo, ma si passa una matrice di argomenti come secondo argomento.

+0

Aspetta cosa? Quindi è un 'NodeList' invece di un' Array'? Non è un 'NodeList' * è * un' Array'? –

+2

No, un 'NodeList' è * non * un' Array'. Tuttavia, fondamentalmente, si comporta proprio come un 'Array' - ha indici numerici e una proprietà' length'. Semplicemente non eredita i metodi standard di 'Array'. Tuttavia, se un 'metodo' ha solo bisogno di indicizzazione e' lunghezza', funzionerebbe, ecco perché questo particolare frammento di codice è valido. –

+0

@TikhonJelvis - Quindi è un 'array' senza i metodi che un 'array' dovrebbe avere. Io vedo. –

3

Avviso .call. Si applica (imposta this a) i risultati di document.querySelectorAll a forEach, in modo che itera su quei risultati anziché sull'array (vuoto) sul lato sinistro del punto.

4

Questo è solo utilizzando [] per ottenere la funzione forEach. Una volta che ha la funzione, utilizza .call per chiamarlo come se fosse un metodo di document.querySelectorAll('input[type="checkbox"]').

Questo è utile perché il risultato di document.querySelectorAll non è un Array, ma si comporta come uno, in modo da poter riutilizzare i Array metodi standard.

Quando si utilizza .call, il primo argomento viene utilizzato come valore this. Cioè, in questo particolare frammento, ogni volta che si incontra this nella sorgente di forEach, è impostato su document.querySelectorAll('input[type="checkbox"]').

Non si può semplicemente chiamare document.querySelectorAll('input[type="checkbox"]').forEach(... direttamente a causa querySelectorAll fa non ritorno un oggetto Array e quindi non avere un metodo forEach.L'intera cosa .call è solo un modo per aggirare questo chiamando forEachcome se fosse un metodo di NodeList, che è ciò che viene effettivamente restituito.