My question is, where do I declare the baz
variable?
Quindi la risposta generica a questa domanda è "dovunque tu voglia", ma ovviamente non è utile e ha delle insidie, quindi ti dirò dove I consiglio di metterlo, e tentare per difendere la mia logica nel miglior modo possibile.
Indipendentemente da dove dichiari una funzione * o una variabile ** in JavaScript, la funzione o la variabile sarà issata nella parte superiore del suo ambito di contenimento ***. Se non vi è alcun ambito di contenimento, sarà implicitamente aggiunto al namespace globale (nei browser questo è window
, in NodeJS questo è global
).
Quando una variabile o una funzione è issata, significa che l'interprete JavaScript farà finta di essere scritto come prima riga dell'ambito di contenimento.
In pratica, questo significa che quando scrivi:
(function () {
...a...
if (...b...) {
var example = ...c...;
// ^^^^^^^^^^^
}
}());
In realtà è valutato come:
(function () {
var example;
//^^^^^^^^^^^
...a...
if (...b...) {
example = ...c...;
}
}());
* Mi riferisco alla dichiarazione delle funzioni qui. OSSIA function name(...) {...}
** Mi riferisco alla dichiarazione delle variabili con var
qui. OSSIA var name
*** L'ambito di contenimento è in genere la funzione di wrapping, ma a volte per vari motivi non esiste una funzione di wrapping.
Isn't it safer to code as follows, where var
is used where the variable is first used?
A causa del sollevamento questa classica best practice diventa suscettibile a semplici errori.
Considera il caso in cui scrivi del codice ...
(function () {
for (var i = 0; i < x.length; i++) {
...do stuff...
if (...something happens...) {
break;
}
}
...more stuff...
...even more stuff...
doSomethingWith(i);
}());
Quindi torni più tardi e devi aggiungere alcune nuove funzionalità, quindi aggiungi:
...more stuff...
for (var i = 0; i < y.length; i++) {
...do stuff...
}
...even more stuff...
Ora, se si combinano i due è facile vedere in questo esempio forzato che la sciatteria ha portato a ridichiarare e ignorare accidentalmente la variabile i
.
Questo potrebbe sembrare sciocco, ma succede sempre. È abbastanza facile se non si prendono attivamente provvedimenti per evitarlo. Questo tipo di problema non è un problema nelle lingue con ambito di blocco, perché i
sarebbe contenuto in ogni ambito del ciclo for
, e per usare doSomethingWith
, avremmo dovuto esporre il valore di i
all'ambito genitore.
Con tutto ciò detto, la tua domanda è davvero una delle migliori pratiche. Questo è intrinsecamente soggettivo e porterà a disaccordo. Pubblicherò la mia opinione e cercherò di difenderla, ma dovrebbe essere trattata come un parere e non come dogma.
Nella mia opinione , le funzioni dovrebbero avere il seguente flusso:
- direttive
- Dichiarazione variabile
- Dichiarazione di funzione
- Istanziazione variabile
- Altro codice
(1) Le direttive sono cose come "use strict"
. Vengono prima per definizione.
(2) La dichiarazione delle variabili che usa var
viene seconda. Potrebbero venire dopo la dichiarazione di funzione, o anche in mezzo, ma ho trovato che li rende più difficili da trovare. Raccomando anche di usare esattamente una var
dichiarazione con ogni var posizionata su righe separate, organizzate alfabeticamente. Ciò impone che le variabili vengano raggruppate insieme e l'ordinamento alfabetico previene la duplicazione accidentale.
(3) La dichiarazione di funzione viene dopo perché le funzioni sono issate come le variabili. Vedere quali API locali sono disponibili all'interno di un determinato ambito è qualcosa che trovo utile.
(4) L'istanziazione variabile viene dopo la dichiarazione di funzione, e nel mio parere dovrebbe essere separato dalla dichiarazione. Sì ci sono circostanze in cui è più facile semplicemente metterle sulla stessa linea, ma come regola generale, non puoi sbagliare nel tenerle separate.
Il ragionamento per questo è duplice.
In primo luogo, la dichiarazione verrà interpretata come successa prima del compito, quindi scrivere un codice che legga il modo in cui l'interprete intende interpretarlo aiuterà a capire.
In secondo luogo, se l'assegnazione viene unita alla dichiarazione, l'ordine inizia improvvisamente a contare e perdi la capacità di alfabetizzare in modo coerente le tue variabili.
Ad esempio:
(function () {
var x = ...x...,
y = ...y...,
length = Math.sqrt(x * x + y * y);
// ^^^^^^ no longer alphabetical
}());
Se si separa la dichiarazione dall'assegnazione, è possibile ottenere i vantaggi di entrambi:
(function () {
var length,
x,
y;
x = ...x...;
y = ...y...;
length = Math.sqrt(x * x + y * y);
}());
(5) Una volta terminato il setup di una funzione, dovrai scrivere il resto del codice. Questo passaggio è il passaggio "resto del codice".
Se hai prestato attenzione a ECMAScript2015, dovresti sapere che ci sono due nuovi modi per dichiarare le variabili: let
e const
.
Queste nuove dichiarazioni di variabili usano scope di blocco. Se assegni una variabile che non verrà mai sovrascritta, utilizza const
, altrimenti utilizza let
.
Tornando a:
Isn't it safer to code as follows, where var
is used where the variable is first used?
let
ti consente di farlo. Se puoi usare let
, smetti di usare var
; usa let
e const
dove le variabili vengono usate per la prima volta; combinare la dichiarazione con l'assegnazione:
Modo ES5:
(function () {
var example;
...
example = ...;
}());
Modo ES2015:
(function () {
...
let example = ...;
}());