Uso corretto di const per la definizione di funzioni in JavaScript


183

Sono interessato se ci sono limiti a quali tipi di valori possono essere impostati utilizzando constJavaScript, in particolari funzioni. È valido? Concesso che funziona, ma è considerato una cattiva pratica per qualsiasi motivo?

const doSomething = () => {
   ...
}

Tutte le funzioni dovrebbero essere definite in questo modo in ES6? Non sembra che questo abbia preso piede, se è così.

Grazie per eventuali commenti!


Sembri porre più domande: 1) "Sono interessato se ci sono limiti a quali tipi di valori possono essere impostati usando const in JavaScript" N. 2) "È valido?" Sì. 3) "è considerata una cattiva pratica per qualsiasi motivo" Immagino che non sia in circolazione da abbastanza tempo per dire qualcosa al riguardo, ma non vedo perché questa dovrebbe essere una pratica pad. Non è molto diverso da var doSomething = <function def>;. 4) "Tutte le funzioni dovrebbero essere definite in questo modo in ES6?" Mi sembra ingombrante. Mi piacciono le dichiarazioni di funzioni. Ognuno di loro.
Felix Kling,

1
Per come la vedo io (opinione, non un dato di fatto), ha senso se si desidera impedire la ridefinizione delle funzioni. Che sia sano o che abbia qualche uso funzionale, è discutibile. Se pensi che si adatti al tuo scenario d'uso, non penso che qualcuno possa discutere la tua decisione e ritenerla cattiva pratica.
Mjh

4
Immagino che la domanda sia cosa vuoi raggiungere const. Vuoi impedirti di ignorare la funzione? Suppongo che tu conosca il tuo codice per non farlo comunque. Vuoi esprimere l'intenzione di doSomething, cioè che detiene una funzione e non cambia il suo valore? Penso che anche le dichiarazioni di funzioni comunichino chiaramente questo intento. Quindi, se hai bisogno di "protezione runtime" dalla sostituzione, prova. Altrimenti non vedo molti benefici. Ovviamente se usassi principalmente var foo = function() {};, userei constinvece di var.
Felix Kling,

5
@FelixKling, "Suppongo che tu sappia il tuo codice per non farlo comunque." - questo è un argomento piuttosto negativo. Altrimenti, non ha alcun senso const.
meandre

Risposte:


253

Non ci sono problemi con ciò che hai fatto, ma devi ricordare la differenza tra le dichiarazioni di funzioni e le espressioni di funzioni.

Una dichiarazione di funzione, ovvero:

function doSomething () {}

Viene sollevato interamente nella parte superiore dell'ambito (e simili lete constanch'essi con ambito di blocco).

Ciò significa che funzionerà quanto segue:

doSomething() // works!
function doSomething() {}

Un'espressione di funzione, ovvero:

[const | let | var] = function () {} (or () =>

È la creazione di una funzione anonima ( function () {}) e la creazione di una variabile, quindi l'assegnazione di quella funzione anonima a quella variabile.

Quindi le solite regole relative al sollevamento di variabili all'interno di un ambito - le variabili con ambito di blocco ( lete const) non si elevano undefinedin cima al loro ambito di blocco.

Questo significa:

if (true) {
    doSomething() // will fail
    const doSomething = function () {}
}

Fallirà poiché doSomethingnon è definito. (Lancerà a ReferenceError)

Se passi all'uso varpuoi ottenere il sollevamento della variabile, ma verrà inizializzato in undefinedmodo che il blocco di codice sopra non funzionerà ancora. (Questo genererà un TypeErrorpoiché doSomethingnon è una funzione al momento in cui la chiami)

Per quanto riguarda le pratiche standard, è sempre necessario utilizzare lo strumento adeguato per il lavoro.

Axel Rauschmayer ha un ottimo post sull'ambito e sul sollevamento, tra cui la semantica es6: variabili e scoping in ES6


7
Vorrei solo aggiungere che le classi es6 usano const internamente per proteggere il nome della classe dalla riassegnazione all'interno della classe.
user2342460

2
Una sottile differenza tra una function a(){console.log(this);} e b const a=_=>{console.log(this);} è se lo si chiama come a.call(someVar);, in una , verrà stampata someVar, in b , verrà stampata window.
Qian Chen,

100

Anche se l'utilizzo constper definire le funzioni sembra un hack, ma presenta alcuni grandi vantaggi che lo rendono superiore (secondo me)

  1. Rende la funzione immutabile, quindi non devi preoccuparti che quella funzione venga modificata da qualche altro pezzo di codice.

  2. Puoi usare la sintassi della freccia grassa, che è più corta e più pulita.

  3. L'uso delle funzioni freccia si occupa dell'associazione thisper te.

esempio con function

// define a function
function add(x, y) { return x + y; }

// use it
console.log(add(1, 2)); // 3

// oops, someone mutated your function
add = function (x, y) { return x - y; };

// now this is not what you expected
console.log(add(1, 2)); // -1

stesso esempio con const

// define a function (wow! that is 8 chars shorter)
const add = (x, y) => x + y;

// use it
console.log(add(1, 2)); // 3

// someone tries to mutate the function
add = (x, y) => x - y; // Uncaught TypeError: Assignment to constant variable.
// the intruder fails and your function remains unchanged


1
E puoi dichiarare due volte la funzione add (x, y), ma non puoi dichiarare due volte const add = ...
TatianaP

33
1. L'immutabilità è un vero vantaggio, ma è molto raro che qualcuno sovrascriva effettivamente una funzione. 2. La sintassi della freccia grassa non è più breve a meno che la tua funzione non possa essere un'espressione. function f(x, y) {ha 18 caratteri, const f = (x, y) => {21 caratteri, quindi 3 caratteri in più. 3. Mantenere questo legame è importante solo se le funzioni sono definite all'interno di un metodo (o altra funzione che ha significato). Al primo livello è inutile. Non sto dicendo che ti sbagli, solo che i motivi che dici non sono terribilmente rilevanti.
Nakedible,

@Nakedible quindi quali sono alcuni altri motivi validi?
Anish Ramaswamy,

13
Uno dei vantaggi della vecchia sintassi delle funzioni è che durante il debug ha un nome.
user949300,

3
Vorrei usare le linter per impedire la rilegatura della dichiarazione di funzione.
Franklin Yu,

32

Sono passati tre anni da quando è stata posta questa domanda, ma proprio ora la sto incontrando. Poiché questa risposta è così in fondo alla pila, per favore permettimi di ripeterla:

D: Sono interessato se ci sono limiti a quali tipi di valori possono essere impostati usando const in JavaScript, in particolari funzioni. È valido? Concesso che funziona, ma è considerato una cattiva pratica per qualsiasi motivo?

Sono stato motivato a fare qualche ricerca dopo aver osservato un prolifico programmatore JavaScript che usa sempre laconst dichiarazione per functions, anche quando non vi è alcun motivo / beneficio apparente.

In risposta a " è considerata una cattiva pratica per qualsiasi motivo? ", Lasciami dire, IMO, sì, lo è, o almeno, ci sono vantaggi nell'usare la functiondichiarazione.

Mi sembra che si tratti in gran parte di preferenze e stile. Ci sono alcuni buoni argomenti presentati sopra, ma nessuno è così chiaro come viene fatto in questo articolo:

Costante confusione: perché uso ancora le dichiarazioni delle funzioni JavaScript di medium.freecodecamp.org/Bill Sourour, guru JavaScript, consulente e insegnante.

Invito tutti a leggere quell'articolo, anche se hai già preso una decisione.

Ecco i punti principali:

Le istruzioni di funzione hanno due chiari vantaggi rispetto alle espressioni di funzione [const]:

Vantaggio n. 1: chiarezza di intenti

Durante la scansione di migliaia di righe di codice al giorno, è utile essere in grado di capire l'intento del programmatore il più rapidamente e facilmente possibile.

Vantaggio n. 2: Ordine di dichiarazione == ordine di esecuzione

Idealmente, voglio dichiarare il mio codice più o meno nell'ordine in cui mi aspetto che venga eseguito.

Questo è lo showtopper per me: qualsiasi valore dichiarato usando la parola chiave const è inaccessibile fino a quando l'esecuzione non lo raggiunge.

Ciò che ho appena descritto sopra ci costringe a scrivere codice che appare sottosopra. Dobbiamo iniziare con la funzione di livello più basso e salire di livello.

Il mio cervello non funziona in questo modo. Voglio il contesto prima dei dettagli.

La maggior parte del codice è scritto da umani. Quindi ha senso che l'ordine di comprensione della maggior parte delle persone segue approssimativamente l'ordine di esecuzione della maggior parte del codice.


1
Puoi commentare un po 'di più la chiarezza delle intenzioni? Ottengo il n. 2, ma per quanto ne so il n. 1 è solo una (pre?) Reiterazione del n. 2. Mi viene in mente un caso, ovvero funzioni che hanno una propria defaultErrorHandlerconst assegnata come una funzione anonima che posso quindi chiamare dai gestori della promessa. Ciò mi consentirebbe di "sovrascrivere" facoltativamente questo gestore di errori predefinito all'interno delle funzioni di cui avevo bisogno. Alcuni devono solo restituire un oggetto errore e altri devono restituire una risposta http, variando i livelli di verbosità. Tuttavia, la struttura del codice può essere un modello familiare a prescindere.
Jake T.,

Forse la mia idea è troppo contorta! Sto solo avvolgendo la mia testa attorno ad alcune nuove pratiche, non ho ancora impiegato molto tempo per implementarle. Solo trovando che mi piace .then( res.success, res.error )molto di più delle funzioni anonime che stavo dichiarando di chiamare res.success(value);. Avere un .then( ..., defaultErrorHandler)modello comune potrebbe essere utile, con una funzione defaultErrorHandler definita di livello superiore e facoltativamente avere un const defaultErrorHandler = error => { ... }dichiarato all'interno di un ambito di funzione come desiderato.
Jake T.

1
@JakeT. RE "Puoi commentare un po 'di più la chiarezza delle intenzioni?". Bene, prima di tutto, quell'affermazione non mi è stata fatta, ma da freecodecamp.org/Bill Sourour, l'autore di quell'articolo. Ma ha molto senso per me. Se leggo "funzione domani ()" allora so immediatamente che è una funzione. Ma se leggo "const tomorrow = () =>", mi fermo un attimo e analizzo la sintassi nella mia testa per determinare finalmente, OK, sì, è una funzione.
JMichaelTX,

1
Un'altra cosa, se ho un lungo script scritto da qualcun altro e voglio vedere tutte le funzioni, posso fare una rapida ricerca su "funzione" per trovarle. O ancora meglio, posso scrivere un rapido JEx RegEx per estrarre tutte le funzioni. IMO, l'istruzione "const" è solo per i dati (non le funzioni) che NON cambieranno.
JMichaelTX,

10

Ci sono alcuni benefici molto importanti nell'uso conste alcuni direbbero che dovrebbe essere usato ovunque possibile a causa di quanto sia deliberato e indicativo.

È, per quanto posso dire, la dichiarazione di variabili più indicativa e prevedibile in JavaScript, e una delle più utili, PERCHÉ è limitata. Perché? Perché elimina alcune possibilità disponibili vare letdichiarazioni.

Cosa puoi dedurre quando leggi un const? Conoscete tutto quanto segue semplicemente leggendo la constdichiarazione di dichiarazione E senza cercare altri riferimenti a quella variabile:

  • il valore è legato a quella variabile (sebbene il suo oggetto sottostante non sia profondamente immutabile)
  • non è possibile accedervi al di fuori del suo blocco contenente immediatamente
  • l'associazione non è mai stata raggiunta prima della dichiarazione, a causa delle regole della zona morta temporale (TDZ).

La seguente citazione è tratta da un articolo che sostiene i vantaggi di lete const. Inoltre risponde più direttamente alla tua domanda sui vincoli / limiti della parola chiave:

Vincoli come quelli offerti da lete constsono un modo potente per rendere il codice più facile da capire. Cerca di accumulare quanti più vincoli possibili nel codice che scrivi. Più vincoli dichiarativi che limitano il significato di un pezzo di codice, tanto più facile e veloce sarà per gli umani leggere, analizzare e comprendere un pezzo di codice in futuro.

Certo, ci sono più regole in una constdichiarazione che in una vardichiarazione: con ambito di blocco, TDZ, assegnazione alla dichiarazione, nessuna riassegnazione. Considerando che le vardichiarazioni segnalano solo l'ambito della funzione. Il conteggio delle regole, tuttavia, non offre molte informazioni. È meglio soppesare queste regole in termini di complessità: la regola aggiunge o sottrae complessità? Nel caso di const, l'ambito del blocco significa un ambito più ristretto dell'ambito della funzione, TDZ significa che non abbiamo bisogno di scansionare l'ambito all'indietro dalla dichiarazione per individuare l'uso prima della dichiarazione e le regole di assegnazione significano che l'associazione manterrà sempre il stesso riferimento.

Più sono le istruzioni vincolate, più semplice diventa un pezzo di codice. Man mano che aggiungiamo vincoli al significato di un'istruzione, il codice diventa meno imprevedibile. Questo è uno dei maggiori motivi per cui i programmi digitati staticamente sono generalmente più facili da leggere rispetto a quelli tipizzati dinamicamente. La digitazione statica pone un grosso vincolo allo scrittore del programma, ma pone anche un grosso vincolo su come il programma può essere interpretato, rendendo il suo codice più facile da capire.

Tenendo presenti questi argomenti, si consiglia di utilizzare constladdove possibile, poiché è l'affermazione che ci offre le minori possibilità di riflessione.

Fonte: https://ponyfoo.com/articles/var-let-const

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.