Azúcar sintáctico y diabetes JavaScript

El azúcar sintáctico es una forma abreviada de comunicar un pensamiento más amplio en un lenguaje de programación.

Me gusta compararlo con las siglas en lenguajes naturales. Al principio, ver un nuevo acrónimo puede resultar confuso, pero una vez que sabes lo que significa, ¡es mucho más rápido!

Con azúcar sintáctico, como con las siglas, ¡puedes GTFAMLH! (ir demasiado lejos y hacer la vida más difícil)

Recién salí de la universidad, creando aplicaciones divertidas en hackatones con mis amigos y en un emocionante viaje de JavaScript para principiantes. Me sentí imparable . Entendí todos los ejemplos de Codecademy, memoricé todas las preguntas de la entrevista inicial. Vi "¿Qué demonios ... JavaScript?" Tantas veces que si un mono rampante gritaba y golpeaba líneas de código al azar en una consola, sabía lo que evaluaría.

Era el momento de subirme a GitHub y compartir mi regalo con el mundo . Abrí el primer proyecto que pude encontrar y comencé a leer. Se veía algo como esto:

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

Momentos después…

Confundido y derrotado, cerré la pestaña del navegador y salí por el día. Esto comenzaría una cadena de mí haciendo lo siguiente:

  1. Descubra una línea de código que en ese momento era solo jeroglíficos de JavaScript.
  2. Sin saber cómo hacer las preguntas correctas y elaborando, posiblemente, las peores búsquedas en Google conocidas por la humanidad.
  3. Molestar a los desarrolladores aleatorios hasta que alguien pudiera "Explicar como si tuviera 5 años", pero al final, seguía confundido por qué alguien escribiría algo así. Probablemente el sadismo .

4. Hacer que haga clic, entender por qué es útil, comprender qué problema resuelve y comprender lo que la gente hizo en el pasado para resolver el problema. ¡Era solo una forma más concisa de escribir código! ¡Es solo azúcar!

5. A veces, usándolo de manerademasiado y empeorando subjetivamente mi código.

6. Encontrar el equilibrio y agregar una gran herramienta a mi kit de herramientas de JavaScript. ?

5. Enjuague y repita unas 20 veces.

¡Ahora estoy aquí para intentar desglosarlo simplemente para ti! Para cada truco de azúcar, incluiré una historia de fondo, un problema que podría ayudar a resolver, cómo podría lograrlo antes del azúcar sintáctico y situaciones en las que es posible que no desee usarlo. ?

Operador ternario

El Ternary Operator es uno de mis favoritos para empezar cuando se habla de azúcar en JavaScript, ya que es muy fácil ir demasiado lejos. Normalmente toma la forma de x ? a : b. Aquí hay un ejemplo más realista:

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

Problema: tengo una variable que depende de que alguna condición sea verdadera o falsa.

Solución de dieta: ¡ Esta es básicamente una forma muy abreviada de hacer una dietaif/else !

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

Cuándo no usarlo: los ternaries son una forma muy simple de expresar rutas de ramificación. En mi opinión subjetiva, lo peor de ellos es que son infinitamente encajables. Entonces, si eres fanático de la seguridad laboral, podrías escribir esta fusión de cerebros.

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

Ejemplo clásico de JavaScript Diabetes. Menos código no significa código más conciso.

Propagación de objetos

Ah, el ejemplo desde el principio que me rompió el corazón. En Javascript, cuando vea ..., según el contexto , será Objeto / Array Spread u Objeto / Array Rest. Vamos a cubrir el Descanso en un momento, así que dejemos eso en un segundo plano.

La difusión consiste básicamente en tomar un único objeto, extraer todos sus pares clave / valor y colocarlos en otro objeto. A continuación, se muestra un ejemplo básico de cómo expandir dos objetos en un nuevo objeto:

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", // }

Problema: tengo un objeto y quiero crear otro objeto que tenga todas las mismas claves, con los mismos valores. Quizás quiero hacer eso con varios objetos, y si hay claves duplicadas, elegir qué claves del objeto ganan.

Solución dietética: se puede utilizar Object.assign()para lograr un efecto similar. Toma cualquier número de objetos como argumentos, da prioridad a los objetos más a la derecha cuando se trata de claves y termina mutando el primer objeto dado. Un error común es no pasar un objeto vacío como primer argumento y mutar accidentalmente un argumento que no pretendía.

Si es difícil de seguir, te alegrará saber que Object Spread lo hace imposible. Aquí hay un ejemplo que replica la versión sintáctica de azúcar.

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 propagación de objetos elimina la posibilidad de una mutación accidental. Por lo tanto, podría hacer cosas, como actualizar el estado de Redux, sin el temor de mantener accidentalmente una referencia que provoque un error de comparación superficial.

? Bonificación? ¡La propagación de rayos funciona de manera muy similar! Pero como no hay claves en las matrices, simplemente la agrega a la nueva matriz como una Array.Prototype.concatllamada.

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

Desestructuración de objetos

Este lo veo con bastante frecuencia en la naturaleza. Ahora, tenemos nuestro nuevo objeto de configuración del ejemplo anterior y queremos usarlo en nuestro código. Puede ver algo como esto esparcido por el código base.

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

Problema: tener que escribir la ruta completa a una clave en un objeto puede resultar bastante pesado y obstruir gran parte del código. Para ser más conciso, sería mejor convertir el valor en una variable para mantener el código ordenado.

Solución dietética: ¡Siempre puedes hacerlo a la antigua! Eso se vería algo así.

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