Sucre syntaxique et diabète JavaScript

Le sucre syntaxique est un raccourci pour communiquer une pensée plus large dans un langage de programmation.

J'aime le comparer aux acronymes des langues naturelles. Au début, voir un nouvel acronyme peut être déroutant, mais une fois que vous savez ce que cela signifie, c'est beaucoup plus rapide!

Avec le sucre syntaxique - comme avec les acronymes - vous pouvez GTFAMLH! (aller trop loin et rendre la vie plus difficile)

J'étais tout juste sorti de l'université, je créais des applications amusantes lors de hackathons avec mes amis et lors d'un voyage à sensations fortes en JavaScript pour débutants. Je me sentais imparable . J'ai compris tous les exemples de la Codecademy, j'ai mémorisé chaque question d'interview frontale. J'ai regardé "Qu'est-ce que… JavaScript?" tellement de fois que si un singe déchaîné criait des lignes de code aléatoires dans une console, je savais à quoi cela donnerait.

Il était temps pour moi de monter sur GitHub et de partager mon cadeau avec le monde . J'ai ouvert le premier projet que j'ai pu trouver et j'ai commencé à lire. Cela ressemblait à quelque chose comme ceci:

function init(userConfig) { const DEFAULT_CONFIG = { removeSpaces: false, allowHighlighting: true, priority: "high", } const config = { ...DEFAULT_CONFIG, ...userConfig }; }

Quelques instants plus tard…

Confus et vaincu, j'ai fermé l'onglet du navigateur et quitté pour la journée. Cela commencerait une chaîne de moi faisant ce qui suit:

  1. Découvrez une ligne de code qui à l'époque n'était que des hiéroglyphes JavaScript.
  2. Ne pas savoir comment poser les bonnes questions et créer probablement les pires recherches Google connues de l'humanité.
  3. Gêner les développeurs aléatoires jusqu'à ce que quelqu'un puisse «expliquer comme si j'avais 5 ans», mais à la fin, on ne sait toujours pas pourquoi quelqu'un écrirait quelque chose comme ça. Sadisme, probablement .

4. Le faire cliquer, comprendre pourquoi il est utile, comprendre quel problème il résout et comprendre ce que les gens ont fait dans le passé pour résoudre le problème. C'était juste une manière plus concise d'écrire du code! C'est juste du sucre!

5. Parfois, en l'utilisant de manièretrop et rendant mon code subjectivement pire.

6. Trouver l'équilibre et ajouter un excellent outil à ma boîte à outils JavaScript. ?

5. Rincer et répéter environ 20 fois.

Maintenant, je suis ici pour essayer de le décomposer simplement pour vous! Pour chaque tour sucré, j'inclurai une histoire, un problème qu'il pourrait aider à résoudre, comment vous pourriez y parvenir avant le sucre syntaxique et des situations où vous ne voudrez peut-être pas l'utiliser! ?

Opérateur ternaire

L'opérateur ternaire est l'un de mes préférés pour commencer quand on parle de sucre en JavaScript, car il est vraiment facile d'aller trop loin. Il prend normalement la forme de x ? a : b. Voici un exemple plus réaliste:

const amILazy = true; const dinnerForTonight = amILazy ? "spaghetti" : "chicken";

Problème: j'ai une variable qui dépend du fait qu'une condition soit vraie ou fausse.

Solution diététique: Il s'agit simplement d'une manière très abrégée de faire un if/else!

const amILazy = true; let dinnerForTonight = null; if(amILazy) { dinnerForTonight = "spaghetti"; } else { dinnerForTonight = "chicken"; }

Quand ne pas l'utiliser: les ternaires sont un moyen très simple d'exprimer des chemins de branchement. À mon avis subjectif, le pire à leur sujet est qu'ils sont infiniment emboîtables. Donc, si vous êtes fan de la sécurité de l'emploi, vous pourriez potentiellement écrire ce fondeur de cerveau.

const canYouFireMe = someCondition1 ? (someCondition2 ? false : true) : false

Exemple classique de diabète JavaScript. Moins de code ne signifie pas un code plus concis.

Propagation d'objets

Ah, l'exemple du début qui m'a brisé le cœur. En Javascript, quand vous voyez ..., en fonction du contexte, cela va être Object / Array Spread, ou Object / Array Rest. Nous allons couvrir Rest dans un peu, alors mettons cela en veilleuse.

La propagation consiste essentiellement à prendre un seul objet, à extraire toutes ses paires clé / valeur et à les placer dans un autre objet. Voici un exemple de base de répartition de deux objets dans un nouvel objet:

const DEFAULT_CONFIG = { preserveWhitespace: true, noBreaks: false, foo: "bar", }; const USER_CONFIG = { noBreaks: true, } const config = { ...DEFAULT_CONFIG, ...USER_CONFIG }; // console.log(config) => { // preserveWhitespace: true, // noBreaks: true, // foo: "bar", // }

Problème: j'ai un objet et je veux créer un autre objet qui a toutes les mêmes clés, avec toutes les mêmes valeurs. Peut-être que je veux faire cela avec plusieurs objets, et s'il y a des clés en double, choisissez les clés de l'objet qui l'emportent.

Solution diététique: vous pouvez utiliser Object.assign()pour obtenir un effet similaire. Il prend n'importe quel nombre d'objets comme arguments, donne la priorité aux objets les plus à droite en ce qui concerne les clés et finit par muter le tout premier objet donné. Une erreur courante consiste à ne pas passer un objet vide comme premier argument et à muter accidentellement un argument auquel vous ne vouliez pas.

Si c'est difficile à suivre, vous serez heureux de savoir que Object Spread rend cela impossible. Voici un exemple qui reproduit la version syntaxique du sucre.

const DEFAULT_CONFIG = { preserveWhitespace: true, noBreaks: false, foo: "bar", }; const USER_CONFIG = { noBreaks: true, } // if we didn't pass in an empty object here, config // would point to DEFAULT_CONFIG, and default config would be // mutated const config = Object.assign({}, DEFAULT_CONFIG, USER_CONFIG);

La propagation d'objets supprime le risque de mutation accidentelle. Vous pouvez donc faire des choses, comme mettre à jour Redux State, sans craindre de garder accidentellement une référence, ce qui entraînerait l'échec de la comparaison superficielle.

? Prime ? La diffusion des rayons Ar fonctionne de manière très similaire! Mais comme il n'y a pas de clé dans les tableaux, cela l'ajoute simplement au nouveau tableau comme un Array.Prototype.concatappel.

const arr1 = ['a', 'b', 'c']; const arr2 = ['c', 'd', 'e']; const arr3 = [...arr1, ...arr2]; // console.log(arr3) => ['a', 'b', 'c', 'c', 'd', 'e']

Destructuration d'objets

Celui-ci que je vois assez souvent dans la nature. Maintenant, nous avons notre nouvel objet de configuration de l'exemple précédent et souhaitons l'utiliser dans notre code. Vous pouvez voir quelque chose comme celui-ci dispersé dans la base de code.

const { preserveWhiteSpace, noBreaks } = config; // Now we have two new variables to play around with! if (preservedWhitespace && noBreaks) { doSomething(); };

Problème: devoir écrire le chemin complet d'une clé dans un objet peut devenir assez lourd et obstruer une grande partie du code. Pour être plus concis, il serait préférable de créer une variable à partir de la valeur pour garder le code net.

Solution diététique: vous pouvez toujours le faire à l'ancienne! Cela ressemblerait à quelque chose comme ça.

const preserveWhitespace = config.preserveWhitepsace; const noBreaks = config.noBreaks; // Repeat forever until you have all the variables you need if (preservedWhitespace && noBreaks) { doSomething(); };

When not to use it: You can actually destructure an object out of an object, and continue to destructure deeper and deeper! Destructuring isn’t the only way to get a key out of an Object. If you find yourself only using destructuring for keys two or three layers deep, chances are you are doing more harm than good to the project.

? Bonus ? Arrays also have destructuring, but they work based off index.

const arr1 = ['a', 'b'] const [x, y] = arr1 // console.log(y) => 'b'

Object Rest

Object Rest goes hand in hand with Object Destructuring, and is very easy to confuse with Object Spread. Once again we use the ... operator, however the context is different. This time, it shows up while destructuring and is intended to gather leftover keys into one object. ?

const { preserveWhiteSpace, noBreaks, ...restOfKeys } = config; // restOfKeys, is an object containing all the keys from config // besides preserveWhiteSpace and noBreaks // console.log(restOfKeys) => { foo: "bar" }

Problem: You want an object that has a subset of keys from another object.

Diet Solution: You could use our old pal Object.assign and delete any of the keys that you don’t need! ?

When not to use it: Using it to create a new object with omitted keys is a common use case. Just be aware that the keys you are omitting in the destructure are still floating around and potentially taking up memory. If you’re not careful, this could cause a bug. ?

const restOfKeys = Object.assign({}, config); delete restOfKeys.preserveWhiteSpace delete restOfKeys.noBreaks

? Bonus ? Guess what? Arrays can do something similar and it works exactly the same!

const array = ['a', 'b', 'c', 'c', 'd', 'e']; const [x, y, ...z] = array; // console.log(z) = ['c', 'c', 'd', 'e']

Wrapping up

JavaScript sugar is great, and understanding how to read it will allow you to enter more diverse code bases and expand your mind as a developer. Just remember that it’s a balancing act between actually being concise, and making your code readable for others and your future self.

While it might feel awesome showing off your shiny new tool, our job as programmers is to leave codebases more maintainable then they were when we entered them.

Here’s a collection of the MDN Documents on what I covered if you want to do some further reading. ?

  • Ternary Operator
  • Spread Syntax
  • Destructuring Assignment
  • Rest Parameters