Utilisation correcte de const pour définir des fonctions en JavaScript

183

Je suis intéressé de savoir s'il existe des limites aux types de valeurs pouvant être définis à l'aide constde JavaScript - en particulier des fonctions. Est-ce valable? Certes, cela fonctionne, mais est-ce considéré comme une mauvaise pratique pour une raison quelconque?

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

Toutes les fonctions doivent-elles être définies de cette manière dans ES6? Il ne semble pas que cela ait pris de l'ampleur, si c'est le cas.

Merci pour vos commentaires!

David Sinclair
la source
Vous semblez poser plusieurs questions: 1) "Je suis intéressé s'il y a des limites à quels types de valeurs peuvent être définis en utilisant const dans JavaScript" No. 2) "Est-ce valide?" Oui. 3) "est-ce considéré comme une mauvaise pratique pour quelque raison que ce soit?" Ce n'est pas très différent de var doSomething = <function def>;. 4) "Toutes les fonctions doivent-elles être définies de cette manière dans ES6?" Cela me semble compliqué. J'aime les déclarations de fonctions. Chacun son propre.
Felix Kling
1
De la façon dont je le vois (opinion, pas un fait), cela a du sens si vous voulez interdire la redéfinition des fonctions. Que ce soit sain d'esprit ou qu'il ait une utilité fonctionnelle - c'est discutable. Si vous pensez que cela correspond à votre scénario d'utilisation, je ne pense pas que quelqu'un puisse contester votre décision et la considérer comme une mauvaise pratique.
Mjh
4
Je suppose que la question est de savoir avec quoi vous voulez réaliser const. Voulez-vous vous empêcher de remplacer la fonction? Je suppose que vous connaissez votre code pour ne pas le faire de toute façon. Voulez-vous exprimer l'intention de doSomething, c'est-à-dire qu'il détient une fonction et ne change pas sa valeur? Je pense que les déclarations de fonction communiquent également clairement cette intention. Donc, si vous avez besoin d'une "protection à l'exécution" contre le remplacement, allez-y. Sinon, je ne vois pas beaucoup d'avantages. Bien sûr, si vous utilisiez principalement var foo = function() {};, j'utiliserais à la constplace de var.
Felix Kling
5
@FelixKling, "Je suppose que vous connaissez votre code pour ne pas le faire de toute façon." - c'est un assez mauvais argument. Sinon, cela n'a aucun sens const.
Meandre

Réponses:

254

Il n'y a aucun problème avec ce que vous avez fait, mais vous devez vous rappeler la différence entre les déclarations de fonction et les expressions de fonction.

Une déclaration de fonction, c'est-à-dire:

function doSomething () {}

Est hissé entièrement au sommet de la lunette (et similaires letet constils sont également à portée de bloc).

Cela signifie que ce qui suit fonctionnera:

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

Une expression de fonction, c'est-à-dire:

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

Est-ce que la création d'une fonction anonyme (function () {} ) et la création d'une variable, puis l'attribution de cette fonction anonyme à cette variable.

Ainsi, les règles habituelles concernant le levage de variables dans une portée - les variables à portée de bloc ( letet const) ne remontent pas undefinedau sommet de leur portée de bloc.

Ça signifie:

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

Échouera car doSomethingn'est pas défini. (Cela lancera un ReferenceError)

Si vous passez à l'utilisation, varvous obtenez votre levée de la variable, mais elle sera initialisée pour undefinedque le bloc de code ci-dessus ne fonctionne toujours pas. (Cela lancera un TypeErrorpuisque doSomethingn'est pas une fonction au moment où vous l'appelez)

En ce qui concerne les pratiques standard, vous devez toujours utiliser l'outil approprié pour le travail.

Axel Rauschmayer a un excellent article sur la portée et le levage, y compris la sémantique es6: Variables et portée dans ES6

tkone
la source
7
Je voudrais juste ajouter que les classes es6 utilisent const en interne pour protéger le nom de la classe contre la réaffectation dans la classe.
user2342460
2
Une différence subtile entre a function a(){console.log(this);} et b const a=_=>{console.log(this);} est que si vous l'appelez comme a.call(someVar);, en a , il imprimera someVar, en b , il imprimera window.
Qian Chen
100

Bien que l'utilisation constpour définir des fonctions semble être un hack, mais cela présente de grands avantages qui le rendent supérieur (à mon avis)

  1. Cela rend la fonction immuable, vous n'avez donc pas à vous soucier de la modification de cette fonction par un autre morceau de code.

  2. Vous pouvez utiliser la syntaxe de la grosse flèche, qui est plus courte et plus propre.

  3. L'utilisation des fonctions fléchées s'occupe de la thisliaison pour vous.

exemple avec 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

même exemple avec 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

gafi
la source
1
Et vous pouvez déclarer deux fois la fonction add (x, y), mais vous ne pouvez pas déclarer deux fois const add = ...
TatianaP
33
1. L'immuabilité est un réel avantage, mais il est très rare qu'une personne écrase réellement une fonction. 2. La syntaxe de la grosse flèche n'est pas plus courte, sauf si votre fonction peut être une expression. function f(x, y) {est de 18 caractères, const f = (x, y) => {est de 21 caractères, donc 3 caractères de plus. 3. Conserver cette liaison n'a d'importance que si les fonctions sont définies dans une méthode (ou une autre fonction qui a un sens). Au plus haut niveau du script, c'est inutile. Je ne dis pas que vous vous trompez, mais simplement que les raisons que vous mentionnez ne sont pas très pertinentes.
Nakedible le
@Nakedible alors quelles sont d'autres raisons valables?
Anish Ramaswamy
13
Un avantage de l'ancienne syntaxe de fonction est que lors du débogage, elle a un nom.
user949300
3
J'utiliserais des linters pour éviter de relier la déclaration de fonction.
Franklin Yu
32

Cela fait trois ans que cette question a été posée, mais je viens de la rencontrer. Puisque cette réponse est si loin dans la pile, permettez-moi de la répéter:

Q: Je voudrais savoir s'il existe des limites aux types de valeurs qui peuvent être définis à l'aide de const dans JavaScript, en particulier des fonctions. Est-ce valable? Certes, cela fonctionne, mais est-ce considéré comme une mauvaise pratique pour une raison quelconque?

J'ai été motivé pour faire des recherches après avoir observé un codeur JavaScript prolifique qui utilise toujoursconst Statement for functions, même lorsqu'il n'y a aucune raison / avantage apparent.

En réponse à " est-ce considéré comme une mauvaise pratique pour une raison quelconque? ", Permettez-moi de dire, l'OMI, oui, ou du moins, il y a des avantages à utiliser la functiondéclaration.

Il me semble que c'est en grande partie une question de préférence et de style. Il y a quelques bons arguments présentés ci-dessus, mais aucun n'est aussi clair que dans cet article:

Confusion constante: pourquoi j'utilise toujours des déclarations de fonction JavaScript par medium.freecodecamp.org/Bill Sourour, gourou JavaScript, consultant et enseignant.

J'exhorte tout le monde à lire cet article, même si vous avez déjà pris une décision.

Voici les principaux points:

Les instructions de fonction présentent deux avantages évidents par rapport aux expressions de fonction [const]:

Avantage n ° 1: Clarté de l'intention

Lorsque vous parcourez des milliers de lignes de code par jour, il est utile de pouvoir comprendre l'intention du programmeur aussi rapidement et facilement que possible.

Avantage n ° 2: Ordre de déclaration == ordre d'exécution

Idéalement, je veux déclarer mon code plus ou moins dans l'ordre dans lequel je m'attends à ce qu'il soit exécuté.

C'est le showstopper pour moi: toute valeur déclarée à l'aide du mot-clé const est inaccessible jusqu'à ce que l'exécution l'atteigne.

Ce que je viens de décrire ci-dessus nous oblige à écrire du code qui semble à l'envers. Nous devons commencer par la fonction de niveau le plus bas et progresser.

Mon cerveau ne fonctionne pas de cette façon. Je veux le contexte avant les détails.

La plupart du code est écrit par des humains. Il est donc logique que l'ordre de compréhension de la plupart des gens suive à peu près l'ordre d'exécution de la plupart des codes.

JMichaelTX
la source
1
Pouvez-vous commenter un peu plus la clarté de l'intention? J'obtiens le n ° 2, mais pour autant que je sache, le n ° 1 n'est qu'une (pré?) Réitération du n ° 2. Je peux penser à un cas, c'est-à-dire à des fonctions ayant leur propre defaultErrorHandlerconst assigné comme une fonction anonyme que je peux ensuite appeler à partir des gestionnaires de promesses. Cela me permettrait éventuellement de «remplacer» ce gestionnaire d'erreurs par défaut dans les fonctions selon mes besoins. Certains doivent simplement renvoyer un objet d'erreur et d'autres doivent renvoyer une réponse http, avec des niveaux de verbosité variables. Pourtant, la structure du code peut être un modèle familier malgré tout.
Jake T.
Peut-être que mon idée est trop compliquée! Je me contente de penser à de nouvelles pratiques, je n'ai pas encore passé beaucoup de temps à les mettre en œuvre. Je trouve que j'aime .then( res.success, res.error )beaucoup plus que les fonctions anonymes que je déclarais simplement appeler res.success(value);. Avoir un .then( ..., defaultErrorHandler)modèle commun pourrait être agréable, avec une fonction defaultErrorHandler définie au niveau supérieur, et éventuellement avoir une const defaultErrorHandler = error => { ... }déclaration dans une portée de fonction comme vous le souhaitez.
Jake T.
1
@JakeT. RE "Pouvez-vous commenter un peu plus la clarté de l'intention?". Eh bien, tout d'abord, cette déclaration ne m'a pas été faite, mais par freecodecamp.org/Bill Sourour, l'auteur de cet article. Mais cela a un sens commun pour moi. Si je lis "fonction demain ()" alors je sais immédiatement que c'est une fonction. Mais si je lis "const tomorrow = () =>", je dois m'arrêter un instant et analyser la syntaxe dans ma tête pour finalement déterminer, OK, ouais, c'est une fonction.
JMichaelTX
1
Autre chose, si j'ai un long script écrit par quelqu'un d'autre, et que je veux voir toutes les fonctions, je peux faire une recherche rapide sur «fonction» pour les trouver. Ou mieux encore, je peux écrire un rapide JS RegEx pour extraire toutes les fonctions. IMO, l'instruction "const" est juste pour les données (pas les fonctions) qui ne changeront PAS.
JMichaelTX
10

Il y a des avantages très importants à utiliser constet certains diraient qu'il devrait être utilisé dans la mesure du possible en raison de son caractère délibéré et indicatif.

C'est, pour autant que je sache, la déclaration de variables la plus indicative et la plus prévisible en JavaScript, et l'une des plus utiles, EN RAISON de sa contrainte. Pourquoi? Parce qu'il élimine certaines possibilités varet letdéclarations.

Que pouvez-vous en déduire lorsque vous lisez un const? Vous savez tout ce qui suit simplement en lisant l' constinstruction de déclaration, ET sans rechercher d'autres références à cette variable:

  • la valeur est liée à cette variable (bien que son objet sous-jacent ne soit pas profondément immuable)
  • il n'est pas accessible en dehors de son bloc contenant immédiatement
  • la liaison n'est jamais accédée avant la déclaration, en raison des règles de zone morte temporelle (TDZ).

La citation suivante est tirée d' un article faisant valoir les avantages de letet const. Il répond également plus directement à votre question sur les contraintes / limites du mot-clé:

Les contraintes telles que celles offertes par letet constsont un moyen puissant de rendre le code plus facile à comprendre. Essayez d'accumuler autant de ces contraintes que possible dans le code que vous écrivez. Plus les contraintes déclaratives limitent ce qu'un morceau de code pourrait signifier, plus il sera facile et rapide pour les humains de lire, d'analyser et de comprendre un morceau de code à l'avenir.

Certes, il y a plus de règles à un const déclaration qu'à une vardéclaration: à portée de bloc, TDZ, assigner à la déclaration, pas de réaffectation. Alors que les varinstructions signalent uniquement la portée des fonctions. Cependant, le comptage de règles n'offre pas beaucoup d'informations. Il vaut mieux peser ces règles en termes de complexité: la règle ajoute-t-elle ou soustrait-elle la complexité? Dans le cas de const, la portée de bloc signifie une portée plus étroite que la portée de la fonction, TDZ signifie que nous n'avons pas besoin de balayer la portée en arrière à partir de la déclaration afin de repérer l'utilisation avant la déclaration, et les règles d'affectation signifient que la liaison conservera toujours le même référence.

Plus les instructions sont contraintes, plus un morceau de code devient simple. Au fur et à mesure que nous ajoutons des contraintes à ce qu'une instruction peut signifier, le code devient moins imprévisible. C'est l'une des principales raisons pour lesquelles les programmes typés statiquement sont généralement plus faciles à lire que les programmes typés dynamiquement. Le typage statique place une grande contrainte sur le rédacteur du programme, mais il place également une grande contrainte sur la façon dont le programme peut être interprété, ce qui rend son code plus facile à comprendre.

Avec ces arguments à l'esprit, il est recommandé d'utiliser const si possible, car c'est la déclaration qui nous donne le moins de possibilités de réflexion.

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

mrmaclean89
la source