2013-03-27 15 views
5

Facendo riferimento a questo tema: Don't make functions within a loop. - jslint errorJSLint - Non fare le funzioni all'interno di un ciclo

Come si gestisce un .each jQuery (function() {...} all'interno di un ciclo for, sapendo che ho bisogno del? contesto dei "per" nel mio "ogni" funzione. Certo avrei potuto mappare ogni richiesta per i parametri a una funzione una funzione dichiarata al di fuori del ciclo, ma dal mio punto di vista, ha un impatto la leggibilità.

Qualche idea?

Grazie in anticipo

risposta

4

Th e problema con funzioni in loop è: questo,

for (var i = 0; i < list.length; i+= 1) { 
    function my_func(i) { 
     console.log(i); 
    } 
    my_func(i); 
} 

Sarà interpretato nel modo:

var my_func; 
for (var i = 0; i < list.length; i+= 1) { 
    my_func = function (i) { 
     console.log(i); 
    } 
    my_func(i); 
} 

A causa del sollevamento variabile. Tutte le dichiarazioni verranno spostate nella parte superiore dello scope (ad esempio la funzione). Quindi in realtà non ha senso definire una funzione in un ciclo for.

Se si desidera eseguire il binding al contatore in un ciclo for, effettuare semplicemente una chiusura.

Giusto per essere chiari:

$("..").each(function() { 
    for(..) { 
    } 
}); 

va bene.

for(..) { 
    $("..").each(function() { 

    }); 
} 

non va bene, perché è equivalente a questo:

var my_func; 
for(..) { 
    my_func = function() { 
     // .. 
    } 
    $("..").each(my_func); 
} 
2

Si suona già come il problema è più con l'avvertimento che con il vostro codice. Sì, sarà bello passare il test JSLint senza avvertimenti, ma alcuni di essi possono essere irragionevoli e causare una inutile rifattorizzazione del codice.

La discussione in questo Q & A è rilevante: Should I use JSLint or JSHint JavaScript validation? Altri strumenti di sfilacciamento sono disponibili con maggiore flessibilità rispetto a JSLint in modo da poter continuare ad essere produttivi con le preferenze di codifica personale, non necessariamente le preferenze di codifica personale di Crockford.

Ti suggerisco di utilizzare un altro strumento per filtrare il tuo JavaScript e non sacrificare la leggibilità o la manutenibilità del tuo codice.

+0

Certo, ma ancora .. Ci costringe a fare buone domande. Il commento di ruffin sul funzionamento ripetuto più volte è chiaramente la ragione di questa regola che ha finalmente un senso. – y0uri

9

Bene, è possibile mantenere il contesto del for nel proprio ciclo, poiché tutto ciò che è in for è in realtà nello stesso contesto di una funzione dichiarata all'inizio.

Quindi prendiamo l'esempio di Frits, ma prima rendiamo questo completamente soddisfatto da JSLint (meno la funzione chiamata nell'errore di ciclo).

/*global console*/ 
var my_func, i, list; 
for (i = 0; i < list.length; i+= 1) { 
    my_func = function (i) { 
     console.log(i); 
    }; 
    my_func(i); 
} 

noti che ogni volta eseguire iterazioni del ciclo, sei redeclaring la funzione my_func. Questo non e buono! Perché ri-dichiarare la stessa funzione più e più volte?

dichiararlo in precedenza, in questo modo:

/*global console*/ 
var my_func, i, list; 

my_func = function (i) { 
    console.log(i); 
}; 

for (i = 0; i < list.length; i+= 1) { 
    my_func(i); 
} 

successo. Ora non si crea una funzione con ogni iterazione. E, come JSLint ti aiuta a realizzare spingendo tutte le tue dichiarazioni var in cima, puoi comunque avere lo stesso contesto.


EDIT: Come @Flame points out, non c'è bisogno di dichiarare la funzione presto con jQuery each e possibile utilizzare una funzione anonima, ma non è una cattiva idea di dichiarare in anticipo, soprattutto se si sta facendo riutilizzare la logica in più chiamate each. I principali take-homes sono capire che 1.) La pratica della dichiarazione anticipata ha ancora vantaggi, e 2.) jQuery invierà ancora argomenti alla tua funzione (qui, ciò che chiamiamo index), sebbene JSLint non sia (e non dovrebbe) lamentarsi delle funzioni anonime utilizzate in each s (jQuery sauce here).

Inizialmente è un po 'meno intuitivo se si è abituati al costrutto anonimo $.each(function() {});, ma è altrettanto semplice.

/*global alert, $ */ 
$("li").each(function(index) { 
    alert(index + ": " + $(this).text()); 
}); 

... si trasforma in ...

/*global $, alert */ 
var fnOutside = function(index) { 
    alert(index + ": " + $(this).text()); 
}; 
$("li").each(fnOutside); 

che potrebbero essere brevemente confusione perché la chiamata di funzione non ha parametri, ma jQuery è ciò che sta spingendo il "indice" parametro alla funzione . Potresti semplicemente prendere l'array contestuale arguments per vedere che è ancora inserito lì se vuoi lasciare il naming out.

Fiddle-ige

Vale a dire, il costrutto for non crea una nuova chiusura. Questo potrebbe preoccuparti. Non è un problema!

+0

hai ragione, questo è il modo per fare felice jslint e mantenere il codice più leggibile possibile. Questa è la soluzione che descrivo come di impatto sulla leggibilità nella mia domanda iniziale. con un singolo parametro va bene, ma se si considera l'utilizzo di 10 ... – y0uri

+1

Certo, mi scuso per andare troppo di base per la tua domanda. Il vero punto cruciale per me è la porzione in grassetto, sopra, nello specifico che * dichiara che all'interno del ciclo si riduce la prestazione * (ogni volta che si ripete la stessa funzione ogni volta) e si rompe la "normalizzazione" logica, che è una ragione sufficiente (imo) per inserirla uno stato leggermente più illeggibile, appena sopra il 'for'. Si può sempre usare un oggetto composto per mantenerlo banalmente più leggibile ('options = {var1:" val1 ", var2:" val2 "...}') o si collega a qualcosa di utile. Ad ogni modo, prendo il consiglio di JSLint in questi casi. – ruffin

+0

@rufin Questo potrebbe confondere brevemente perché la chiamata alla funzione non ha parametri, ma jQuery è ciò che sta spingendo il parametro "indice" alla funzione. jQuery inserisce anche un secondo param, ovvero l'elemento, che potrebbe essere meno confuso dell'uso di '$ (this) .'/* global $, alert */var fnOutside = function (index, el) {alert (index +": " + $ (el) .text()); }; $ ("li") .each (fnOutside); – user2720770

Problemi correlati