2015-11-18 12 views
9

Ho un Javascript snippet con una chiamata di funzione ricorsiva:JSLint sostiene alcune chiamate di funzione ricorsiva sono "fuori portata"

(function() { 
    "use strict"; 

    var recurse = function (x) { 
     if (x <= 0) { 
      return; 
     } 
     return recurse(x - 1); 
    }; 

    recurse(3); 
}()); 

Questo non fa altro che chiamare se stesso un paio di volte, ma funziona.

incollando il sopra in JSLint mi dà questo errore:

'recurse' is out of scope. 

Tuttavia, se mi incollo nel seguente frammento, (usando una dichiarazione di funzione, invece di var):

(function() { 
    "use strict"; 

    function recurse(x) { 
     if (x <= 0) { 
      return; 
     } 
     return recurse(x - 1); 
    } 

    recurse(3); 
}()); 

JSLint ama esso, nessun errore.

So che l'obiettivo di JSLint è di prevenire i bug nel codice Javascript. Qualcuno sa perché JSLint pensa che il primo sia un Javascript errato? Quale errore sto impedendo non facendo una chiamata ricorsiva nel primo modo?

+1

JSLint è un trascinamento. Il primo non è male JavaScript. [JSHint] (http://jshint.com) non ha problemi con esso. Né [ESLint] (http://eslint.org). –

+0

Penso che quello che JSLint sta * cercando * di dirti è che al momento in cui definisci la tua espressione di funzione, la variabile 'recurse' ha il valore' undefined'. Questo non è un problema, ovviamente, perché nel momento in cui effettivamente * chiami * la tua funzione, 'recurse' * è * definita. – apsillers

+1

No, gratta questo - se fai semplicemente 'var recurse;' e poi 'recurse = function ... 'questo fa sparire l'avvertimento senza cambiare la situazione che ho descritto sopra. Il vero problema è che JSLint non registra 'recurse' come in-scope finché non viene valutata l'espressione' var recurse = ... '(ma il lato sinistro dovrebbe essere sufficiente per farlo) . – apsillers

risposta

4

Non c'è niente di sbagliato in nessuno dei due stili. Per quanto posso dire, questo è un avvertimento inappropriato.

Il problema sembra essere che una dichiarazione di variabile che include un'assegnazione non fa sì che JSLint registri la presenza del nome della variabile dichiarata in ambito fino a quando l'intera assegnazione non viene valutata. Cioè, quando JSLint legge var recurse = ..., non si rende conto che recurse è una variabile dichiarata fino a quando non valuta il lato destro dell'assegnazione. In questo caso, il lato destro include una funzione che utilizza la variabile dichiarata recurse, ma JSLint non sapeva ancora dell'esistenza di recurse, perché non aveva terminato l'analisi dell'intero compito.

Si consideri che questo codice funziona esattamente lo stesso come var esempio, ma produce nessun avviso in JSLint:

(function() { 
    "use strict"; 

    var recurse; 
    recurse = function (x) { 
     if (x <= 0) { 
      return; 
     } 
     return recurse(x - 1); 
    }; 

    recurse(3); 
}()); 

disegnando var recurse come una dichiarazione separata, JSLint prima viene a sapere che recurse viene dichiarata nello scope corrente e quindi analizza il compito. Con il tuo var recurse = ... combinato (che, ancora una volta, non è sbagliato), JSLint analizza erroneamente il compito prima e poi apprende dell'esistenza di recurse.

+0

Contrassegnare questo come risposta accettata finché qualcuno non mi dice cosa potrebbe andare storto con il primo esempio. Grazie! – Amasa

+1

Scommetto che "recurse" è utilizzato all'interno della definizione "recurse" e il caso limite non è stato ancora catturato. Funziona in [la vecchia versione di JSLint] (http://rufwork.com/jslint), per quello che vale. [Dopo una riscrittura quasi completa a maggio] (https://github.com/douglascrockford/JSLint/commit/557afd32bcaa35480d31a86f02d3a8c06a4e5b5c#diff-01d3d81a6eb6d82af3c377b55dc4fa28), Crockford ha preso il nuovo fuori dalla beta qualche tempo fa, ma ha ancora un numero di bug. Puoi segnalarlo al suo [gruppo Google+] (https://plus.google.com/communities/104441363299760713736). È un bug legittimo, penso. – ruffin

0

Quando si definisce la funzione, la variabile recurse non è ancora definita, ecco perché JSLint dice che è fuori portata, affermando che potrebbe essere indefinito e tale punto.