Combien devrais-je utiliser 'let' vs 'const' dans ES6?

214

J'ai écrit beaucoup de code ES6 pour io.js récemment. Il n’ya pas beaucoup de code dans la nature à apprendre, alors j’ai l’impression de définir mes propres conventions au fur et à mesure.

Ma question est quand utiliser constvs let.

J'ai appliqué cette règle: si possible, utilisez const. Utilisez uniquement letsi vous savez que sa valeur doit changer. (Vous pouvez toujours revenir en arrière et changer un consten un lets'il s'avère que vous devez changer sa valeur plus tard.)

La principale raison de cette règle est qu'il est facile à appliquer de manière cohérente. Il n'y a pas de zones grises.

En réalité, lorsque j’applique cette règle, en pratique, 95% de mes déclarations le sont const. Et cela me semble bizarre. Je n'utilise que letpour des choses comme idans une forboucle, ou occasionnellement pour des choses comme les totaux accumulés de Fibonacci (qui ne sont pas très fréquents dans la vie réelle). Cela m'a surpris - il s'avère que 95% des «variables» dans mon code ES5 à ce jour étaient pour des valeurs qui ne varient pas. Mais voir constpartout dans mon code me semble mal.

Ma question est donc la suivante: est-il acceptable d’utiliser constautant? Devrais-je vraiment faire des choses comme const foo = function () {...};?

Ou devrais-je réserver constpour ce genre de situations où vous codez en dur un littéral en haut d'un module - le genre que vous faites en majuscules, comme const MARGIN_WIDTH = 410;?

callum
la source
7
Je soupçonne que cette question est principalement basée sur l'opinion et est donc susceptible d'être fermée, mais mes 2 cents: C'est OK d'utiliser constautant.
Jhominal
15
function foo() {...}est meilleur que<anything> foo = function() {...}
OrangeDog
12
@ OrangeDog Je voudrais voir votre explication à ce sujet, puisque j'ai conclu exactement le contraire. Une mise en garde function foo() {...}peut entraîner une confusion mineure lors du débogage, en raison du levage. De plus, son existence signifie que nous avons deux constructions qui font la même chose, mais que l’une d’elles ne fonctionne que dans un contexte très spécifique. (Vous pouvez utiliser une expression de fonction n'importe où une expression peut exister, mais vous ne pouvez utiliser qu'une déclaration de fonction au niveau de l'instruction.) Si vous préférez être bref, le problème pourrait simplement être que la syntaxe de l'expression de fonction utilise l'intégralité du mot function.
Keen
11
Les traces de pile portent le nom de la fonction au lieu de anon. Le levage est bon et permet de définir les fonctions dans un ordre naturel, sans avoir à craindre que foo ne soit pas défini.
OrangeDog
1
Ce sont de bons points à prendre en compte, mais je ne suis pas encore convaincu. Les débogueurs modernes réussissent bien à choisir le bon nom d'affichage pour votre fonction en fonction du symbole auquel vous l'attribuez (le cas échéant, vous pouvez utiliser une expression de fonction nommée). La déclaration de l'ordre naturel des fonctions est hautement subjective. Il serait peut-être raisonnable de penser que l'ordre naturel consiste à définir les éléments de base, puis à définir ceux qui les utilisent.
Keen

Réponses:

183

Ma réponse ici n'est pas spécifique à javascript.

En règle générale, dans toute langue qui me permet de le faire de manière semi-facile, je dirais que vous devez toujours utiliser const / final / readonly / quel que soit le nom utilisé dans votre langue, lorsque cela est possible. La raison est simple, il est beaucoup plus facile de raisonner sur le code lorsqu'il est évident de savoir ce qui peut changer et ce qui ne peut pas changer. Et en plus de cela, dans de nombreuses langues, vous pouvez obtenir un support d’outil vous indiquant que vous faites quelque chose de mal lorsque vous affectez accidentellement une variable que vous avez déclarée comme const.

Revenir en arrière et changer un const en un let est extrêmement simple. Et aller par défaut vous fait réfléchir à deux fois avant de le faire. Et c'est dans de nombreux cas une bonne chose.

Combien de bugs avez-vous vu impliquant des variables changeant de manière inattendue? J'imagine beaucoup. Je sais que la majorité des bogues que je vois impliquent des changements d'état inattendus. Vous ne vous débarrasserez pas de tous ces bugs en utilisant généreusement const, mais vous vous débarrasserez de beaucoup d'entre eux!

En outre, de nombreux langages fonctionnels ont des variables immuables où toutes les variables sont constantes par défaut. Regardez Erlang par exemple ou F #. Le codage sans affectation fonctionne parfaitement dans ces langues et est l’une des nombreuses raisons pour lesquelles les gens aiment la programmation fonctionnelle. Il y a beaucoup à apprendre de ces langages sur la gestion d'état afin de devenir un meilleur programmeur.

Et tout commence par être extrêmement libéral avec const! ;) Il ne reste plus que deux personnages à écrire, alors allez-y et consttout le reste!

wasatz
la source
45
constest deux personnages de plus que let...
OrangeDog
72
Mais 5 personnages moins qu'immuable.
Cerad
7
Cela ressemble beaucoup à utiliser valdans Scala (qui déclare une variable immuable) et à n’utiliser que var(l’équivalent mutable) lorsque nous ne pouvons pas utiliser val. En d'autres termes, nous déclarons les variables immuables par défaut et n'introduisons la mutabilité que lorsque nous en avons absolument besoin (ce qui peut être simplement dû au fait que l'approche mutable est plus propre).
Kat
7
Je suis d’accord avec cette réponse, mais gardez à l’esprit que les choses ne sont pas si évidentes lorsque vous travaillez avec des objets simples ou des tableaux, car leurs propriétés peuvent changer même s’ils ont été définis avec «const». J'avais pensé à 'const' fonctionner comme object.freeze mais ce n'est pas le cas.
backdesk
2
@ Cerad Vouliez-vous dire «moins de 4 personnages» ou est-ce que je manque une blague ici?
Mathias Bynens
57

Soyez prudent, car les constclés d'objet sont mutables.

De là: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const

les clés d'objet ne sont pas protégées

Considérons cet exemple:

const colors = {red: "#f00"}; 
console.log(colors); // { "red": "#f00" }

colors.red = "#00f";
colors.green = "#0f0";
console.log(colors); // { "red": "#00f", "green": "#0f0" }

Même chose pour les tableaux:

const numbers = [1, 2, 3];
console.log(numbers); // [ 1, 2, 3 ]

numbers.push(4);
console.log(numbers); // [ 1, 2, 3, 4 ]

Je n'ai pas encore décidé moi-même, mais j'envisage d'utiliser constpour tous les non-tableaux / non-objets et letpour les objets / les tableaux.

lax4mike
la source
34
Vrai, mais attendu OMI - ce qui est constant est la référence d’objet assignée à votre const. colors = numbersne fonctionnera pas, comme prévu. Si vous souhaitez protéger les propriétés de votre objet, vous pouvez utiliser Object.freeze() developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Josef Engelfrost
16
Trompeur. C'est immuable. Mais les propriétés réelles de l'objet ne le sont pas.
Gaston Sanchez
1
+1 Oui, la référence est protégée, mais pour ce qui est de la question , il est assez ridicule d'utiliser, par exemple const moment = require('moment'), à moins que vous ne soyez du genre à craindre que quelqu'un essaie de le faire moment = dead.fish(() => pizza)plus tard.
MaxWell
5
Peut-être plus réaliste de s'inquiéter moment = Date.now(). Mais dans tous les cas, si le code suppose un invariant, je ne vois aucun mal à l’appliquer lorsque cela est possible.
James M.
3
Personne n'a dit qu'ils n'étaient pas immuables, cependant. C'est un malentendu courant de penser que l'objectif de const est de le rendre immuable, lorsqu'il s'agit de garantir que le nom ne fera jamais référence à un objet différent de celui pour lequel il avait été initialisé.
Monokrome
25

Ne t'inquiète pas pour ça. constest un ajout étonnant à JavaScript, et je vous recommanderais de l’utiliser dans tous les endroits où cela fait sens. Cela rend le code plus robuste.

En ce qui concerne les objets, constprotégera votre variable contre la réaffectation, mais si vous avez besoin d’objets immuables, vous aurez besoin de la Object.freezeméthode, voir ci-dessous.

const immutableOject = Object.freeze({immutableProperty: 'foo'});

constprotégera uniquement contre la réaffectation, et la freezeméthode protégera toutes les propriétés immédiates. Si vous souhaitez que toutes les propriétés imbriquées soient également immuables, vous devez les récursivement freeze.

clean_coding
la source
14
Notez que Object.freezec'est peu profond.
Mathias Bynens
@ MathiasBynens Je suis tombé sur ce commentaire et je suis curieux de savoir ce que vous entendiez exactement par cela. Pourriez-vous élaborer?
Cole Roberts
@ColeRoberts Le concept de l'immutabilité superficielle, c'est quand la référence d'objet lui-même est immuable, mais que les propriétés peuvent toujours être changées. Le mot clé const n'engendre qu'une faible immuabilité. Vous devez donc utiliser Object.freeze si toutes les propriétés doivent également être immuables.
clean_coding
3
@ColeRoberts Cela signifie que les valeurs d'objet dans un objet gelé (c'est-à-dire des objets imbriqués) peuvent toujours être mutées. Voir mathiasbynens.be/notes/es6-const#immutable-values pour plus d'informations.
Mathias Bynens
19

Dans mon ES6 constn’est pas une question d’immutabilité , j’explique ce que constsignifie exactement selon les spécifications.

Sur la base de ces faits objectifs, voici ma préférence personnelle:

[…] Il est logique d'utiliser letet constcomme suit dans votre code ES6:

  • utiliser constpar défaut
  • à utiliser uniquement letsi une nouvelle liaison (c'est-à-dire toute forme de réaffectation) est nécessaire
  • ( varne devrait pas être utilisé dans ES6)

Aussi subjectif que cela puisse être, c'est un fait que cela correspond le mieux à l'intention de la spécification.

Les personnes qui utilisent letpar défaut traitent généralement les constvariables comme des constantes (ce qu'elles ne sont pas nécessairement, à dessein!). À chacun son goût, mais je préfère utiliser les choses pour les buts pour lesquels elles ont été conçues, et non pour des raisons inventées que les gens attribuent en se basant sur un malentendu.

Utiliser constuniquement pour les constantes revient à utiliser l' <aside>élément HTML uniquement pour le contenu de la barre latérale.

Mathias Bynens
la source
2
Pourquoi voudriez-vous nommer quelque chose constsi ce n'est pas constant?
nu everest
3
@nueverest Parce que ce constn'est pas pour ça . Avez-vous lu ce qui précède?
Mathias Bynens
2
@ MathiasBynens Je pense que le problème (seulement?) constEst qu'il s'appelle const. C'est un nom idiot (en javascript) qui confond beaucoup de développeurs (tous?) Au début. IMO serait mieux si on constm'avait appelé let(surtout parce que letc'est plus court mais constbeaucoup plus commun) et letqu'on appelle autre chose.
MrN00b
@ MathiasBynens Je comprends, mais pourquoi l'appeler comme ça? Cela crée une énorme confusion, comme le montre cette page.
jtr13
4

Mon approche personnelle, pensée pour aider à la lisibilité et à la compréhension du code:


letne concerne que les variables à vie courte, définies sur une seule ligne et non modifiées après. Généralement, les variables qui ne sont là que pour diminuer le nombre de saisies. Par exemple:

for (let key in something) {
  /* we could use `something[key]` for this entire block,
     but it would be too much letters and not good for the
     fingers or the eyes, so we use a radically temporary variable
  */
  let value = something[key]
  ...
}

constpour tous les noms connus pour être constants sur tout le module. Non compris les valeurs constantes localement. Dans valuel'exemple ci-dessus, par exemple, la portée est constante et elle peut être déclarée avec const, mais comme il existe de nombreuses itérations et que, pour chacune d'entre elles, il existe une valeur du même nom , "valeur", qui pourrait amener le lecteur à penser qu'il valueest toujours le même. Les modules et les fonctions sont le meilleur exemple de constvariables:

const PouchDB = require('pouchdb')
const instantiateDB = function () {}
const codes = {
  23: 'atc',
  43: 'qwx',
  77: 'oxi'
}

varpour tout ce qui peut ou non être variable. Les noms qui peuvent confondre les lecteurs du code, même s’ils sont constants localement et qu’ils ne conviennent pas let(c’est-à-dire qu’ils ne sont pas complétés dans une simple déclaration directe), demandent à être déclarés avec var. Par exemple:

var output = '\n'
lines.forEach(line => {
  output += '  '
  output += line.trim()
  output += '\n'
})
output += '\n---'

for (let parent in parents) {
  var definitions = {}
  definitions.name = getName(parent)
  definitions.config = {}
  definitions.parent = parent
}

Autres commentaires et futures mises à jour possibles ici .

fiatjaf
la source
10
ce deuxième extrait de code ressemble à une arme à feu.
Julian
1

JavaScript est un peu spécial en ce que les variables peuvent être des fonctions et autres, mais considérons en C #, Java ou un autre langage de style C similaire:

const public void DoSomething()

C'est constétrange, et c'est parce que les déclarations de méthode dans ces langages ne peuvent pas changer, une fois qu'elles sont compilées dans quelque chose d'autre, c'est ce qu'elles font, peu importe ce qui se passe (en ignorant quelques horribles piratages pouvant exister).

Pourquoi JavaScript devrait-il être différent? Donc, ce n'est pas compilé, mais cela ne signifie pas que nous devrions jeter la sécurité que les compilateurs peuvent fournir. L'utilisation du constmot clé nous donne plus de sécurité, ce qui conduira sûrement à des applications plus robustes.

Joe
la source