Dove dichiarare una variabile e definire una funzione in Javascript?

1

Sto leggendo il libro JavaScript: The Good Parts .

A pagina 113 raccomanda le espressioni di funzione invece delle istruzioni di funzione, perché le istruzioni sono soggette a sollevamento:

The statement:

function foo( ) {}

means about the same thing as:

var foo = function foo( ) {};

Throughout this book, I have been using the second form because it makes it clear that foo is a variable containing a function value.

Ulteriore JSHint mette in guardia contro le istruzioni di funzione definite in un blocco, ad es. (il mio esempio):

if (foo) {
    function baz() {}
}

... ad es. perché il supporto per questo non è coerente tra i motori javascript; produce il seguente messaggio di errore:

Function declarations should not be placed in blocks. Use a function expression or move the statement to the top of the outer function.

Un work-around consigliato è un'espressione di funzione, ad es. (il mio esempio):

if (foo) {
    baz = function() {}
}

La mia domanda è, dove posso dichiarare la variabile baz ?

La fine di pagina 36 (la sezione Ambito del capitolo Funzioni) dice,

In many modern languages, it is recommended that variables be declared as late as possible, at the first point of use. That turns out to be bad advice for JavaScript because it lacks block scope. So instead, it is best to declare all of the variables used in a function at the top of the function body.

Significa che è meglio dichiarare la variabile baz nella parte superiore della funzione?

Ad esempio, in questo modo:

function(foo) {
    // declare variables
    var baz;
    // implementation
    if (foo) {
        baz = function() {}
    }
}

Questa è una buona pratica, o sto fraintendendo qualcosa, leggendo troppo in esso? Temo che sia più difficile da mantenere: perché separa la dichiarazione di baz (cioè var baz; ) dalla sua inizializzazione. Se rinominare o eliminare uno ma non l'altro, improvvisamente la variabile esisterebbe a livello globale.

Non è più sicuro codificare come segue, dove viene utilizzato var dove viene utilizzata per la prima volta la variabile?

function(foo) {
    // implementation
    if (foo) {
        var baz = function() {}
    }
}

Comprendo che quest'ultima funzionalità è equivalente alla precedente. Il secondo è contrario a uno stile di codifica best-practice per Javascript?

    
posta ChrisW 25.10.2016 - 10:55
fonte

5 risposte

3

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:

  1. direttive
  2. Dichiarazione variabile
  3. Dichiarazione di funzione
  4. Istanziazione variabile
  5. 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. 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 = ...;
}());
    
risposta data 25.10.2016 - 15:53
fonte
5

Le variabili Javascript hanno solo 2 ambiti, globali e locali. Una variabile dichiarata all'interno di una funzione (all'interno di un IF o meno) è accessibile all'intera funzione.

Personalmente dichiaro le variabili verso la parte superiore di una funzione per motivi di chiarezza e tenendo presente quanto sopra. Pertanto sono d'accordo con il consiglio dato nel tuo libro.

Potresti voler esaminare "let" e "const", parte di ECMAScript 2015 (ES6).

    
risposta data 25.10.2016 - 11:13
fonte
1

I fear it makes it harder to maintain: because it separates the declaration of baz (i.e. var baz;) from its initialization. If I rename or delete one but not the other then suddenly the variable would exist at global scope.

Non sono sicuro di vedere il problema qui, davvero. Ogni volta che cambi un nome di variabile in un posto, devi anche cambiargli tutti gli altri utenti. Altrimenti provoca un problema.

Questo è vero indipendentemente dal fatto che dichiari la variabile nel momento in cui la funzione viene definita. È vero che mettere la dichiarazione in cima aggiunge un'occorrenza extra di quella variabile, ma è banale (e non è probabile che manchi se hai una pratica di dichiarare sempre le variabili in cima).

D'altra parte, la dichiarazione delle variabili nella parte superiore della funzione consente di evitare le collisioni accidentali dei nomi e rende facile vedere in un unico punto quali variabili esistono all'interno dell'ambito.

    
risposta data 25.10.2016 - 11:31
fonte
0

La Guida di stile JavaScript di Google consiglia quanto segue:

Instead use a variable initialized with a Function Expression to define a function within a block:

if (x) {
  var foo = function() {};
}

Non hanno una raccomandazione che devi dichiarare le variabili nella parte superiore della funzione (prima che vengano utilizzate).

Né JSLint né JSHint avvertono che ciò è sbagliato.

    
risposta data 25.10.2016 - 11:35
fonte
0
function(foo) {
// implementation
if (foo) {
    var baz = function() {}
 }
}

Questo fa sembrare che baz abbia scope per il blocco if, ma è orientato all'intera funzione.

Mantenerlo in cima per segnalare che è nell'intero ambito della funzione è una buona idea.

Questo stile è visto anche in altri linguaggi di programmazione. Ad esempio in ML inizialmente dichiariamo tutte le variabili in un blocco usando let .

    
risposta data 25.10.2016 - 15:12
fonte

Leggi altre domande sui tag