Recientemente escribí sobre las nuevas funciones introducidas en ES2020... Si bien algunas de estas oportunidades son interesantes, no hay ninguna que merezca ser llamada "revolucionaria". Esto es comprensible dado el hecho de que la especificación JS se actualiza con bastante frecuencia en estos días. Resulta que quienes trabajan en el estándar simplemente tienen menos oportunidades de introducir constantemente algo especial en el lenguaje, como módulos ES6 o funciones de flecha. Pero esto no significa que algo exclusivamente nuevo no aparezca finalmente en el idioma. De hecho, de esto es de lo que quiero hablar hoy. Me gustaría hablar de 4 posibilidades que, a largo plazo, se pueden llamar revolucionarias. Ahora se encuentran en diferentes etapas del proceso.
coordinación de propuestas. Esto, por un lado, significa que es posible que nunca los veamos en JavaScript y, por otro lado, la presencia de tales oraciones nos da la esperanza de que, no obstante, algún día las encontraremos en el idioma.
Decoradores
Comenzaremos con la función que probablemente sea la que se solicite con más frecuencia para ser incluida en el idioma, y alrededor de la cual se ha suscitado bastante entusiasmo. Hace un par de años, escribieron sobre ella literalmente en todas partes. Se trata de decoradores .
Es posible que ya esté familiarizado con los decoradores. Especialmente si escribe en TypeScript. Este es, en esencia, un concepto de metaprogramación destinado a dar al desarrollador la capacidad de "inyectar" su propia funcionalidad en las clases, en sus campos y métodos individuales, y en última instancia, hacer que las clases sean programables.
Eche un vistazo al siguiente ejemplo:
function sealed(constructor: Function) {
Object.seal(constructor);
Object.seal(constructor.prototype);
}
@sealed
class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
greet() {
return "Hello, " + this.greeting;
}
}
Aquí decidí proceder con precaución y di un ejemplo del uso de decoradores de TypeScript . Hice esto principalmente para mostrar la idea general. En el fragmento de código anterior, creamos un decorador
sealed
y lo aplicamos a la clase Greeter
. Como puede ver fácilmente, un decorador es simplemente una función que tiene acceso al constructor de la clase a la que se aplica (este es el objetivo). Usamos una referencia a un constructor, así como un método Object.seal()
para hacer que la clase no sea extensible.
Para aplicar un decorador a una clase, escribimos el nombre del decorador con un icono
@
justo antes de la declaración de la clase. Como resultado, resulta que antes de la declaración de clase aparece una construcción del formulario @[name]
, que en nuestro caso se parece a @sealed
.
Puede verificar la funcionalidad del decorador compilando este código TS con la opción habilitada
experimentalDecorators
e intentando cambiar el prototipo de clase:
Greeter.prototype.test = "test"; // ERROR
Como resultado, ahora debería tener una comprensión general de por qué se necesitan decoradores. Pero me gustaría tocar aquí una cuestión difícil. Se trata del estado de aprobación de la propuesta de decoradores.
Decidí usar TypeScript para demostrar decoradores por una buena razón. El caso es que hace unos años existe una propuesta para incorporar decoradores en JavaScript. Y ahora está "sólo" en la 2ª etapa de acuerdo de 4. Tanto la sintaxis como las capacidades de los decoradores de esta propuesta están en constante cambio. Pero eso no impide que la comunidad JS utilice este concepto. Para estar convencido de esto, basta con mirar grandes proyectos de código abierto como TypeScript o Angular v2 +.
Es cierto que todo esto, con el tiempo y a medida que se desarrolla la propuesta, lleva a un problema relacionado con la incompatibilidad de especificaciones. Es decir, la especificación del decorador ha evolucionado mucho desde que se hizo la propuesta, pero muchos proyectos aún no la han implementado. El ejemplo de TypeScript que se muestra arriba es una demostración de la implementación de una versión anterior de la propuesta. Lo mismo puede decirse de Angular, e incluso de Babel (aunque, en el caso de Babel, podemos decir que ya se está trabajando para implementar una versión más nueva de esta especificación). En general, la versión más reciente de la propuesta, que utiliza una palabra clave
decorator
y una sintaxis adecuadas para la vinculación, aún no ha encontrado ningún uso notable.
La conclusión es que los decoradores tienen el potencial de cambiar la forma en que escribimos el código. Y estos cambios ya se están mostrando, a pesar de que los decoradores aún se encuentran en las primeras etapas. Sin embargo, dado el estado actual de las cosas, los decoradores solo están fragmentando a la comunidad y creo que aún no están listos para un uso realmente serio. Aconsejaría a aquellos que estén interesados en decoradores que esperen un poco antes de introducirlos en producción. Mi recomendación, sin embargo, no se aplica a quienes usan frameworks que usan decoradores (como Angular).
Reinos
Ahora reduzcamos un poco la velocidad y hablemos de una característica que no es tan compleja como los decoradores. Estamos hablando de áreas .
Es posible que ya se haya encontrado en situaciones en las que necesite ejecutar su propio código o código de terceros, pero al mismo tiempo, hágalo de tal manera que este código no afecte el entorno global. Muchas bibliotecas, especialmente las de navegador, funcionan a través del objeto global
window
. Como resultado, pueden interferir entre sí en caso de que el proyecto utilice demasiadas bibliotecas fuera del control del desarrollador. Esto puede provocar errores.
La solución actual del navegador a este problema es utilizar los elementos
<iframe>
y, en algunos casos especiales, en el uso de trabajadores web. En el entorno de Node.js, el mismo problema se resuelve usando un módulo vm
o usando procesos secundarios . La API de Realms está diseñada para resolver estos problemas.
Esta API tiene como objetivo permitir a los desarrolladores crear entornos globales separados llamados ámbitos. Cada una de estas áreas tiene sus propias entidades globales. Eche un vistazo al siguiente ejemplo:
var x = 39;
const realm = new Realm();
realm.globalThis.x; // undefined
realm.globalThis.x = 42; // 42
realm.globalThis.x; // 42
x; // 39
Aquí creamos un nuevo objeto
Realm
usando el constructor apropiado. A partir de ahora, tenemos acceso completo al nuevo alcance y sus objetos globales a través de una propiedad globalThis
(introducida en ES2020). Aquí puede ver que las variables de la "incubadora" principal están separadas de las variables en el alcance que creamos.
En general, la API de Realms está planificada como un mecanismo muy simple, pero es un mecanismo útil. Esta API tiene un conjunto de casos de uso muy específico. No nos da un mayor nivel de seguridad o la capacidad de código multiproceso. Pero perfectamente, sin crear una carga innecesaria en el sistema, hace frente a su tarea principal, proporcionando capacidades básicas para crear entornos aislados.
La propuesta de la API de Realms se encuentra actualmente en la etapa 2 de negociación. Cuando finalmente alcance el estándar, uno esperaría que se usara en bibliotecas "pesadas" que dependen del alcance global, en editores de código de espacio aislado en línea, en varias aplicaciones dirigidas pruebas.
Hacer expresiones
La sintaxis de JavaScript, como la sintaxis de la mayoría de los lenguajes de programación, incluye declaraciones y expresiones. La diferencia más notable entre estas construcciones es que las expresiones se pueden usar como valores (es decir, se pueden asignar a variables, pasar a funciones, etc.), mientras que las declaraciones no se pueden usar como tales.
Debido a esta distinción, las expresiones son la opción más preferida para un código más limpio y compacto. En JavaScript, puede ver esto observando la popularidad de las expresiones de función, que incluyen funciones de flecha, frente a declaraciones de función, declaraciones de función. Se ve la misma situación si comparamos los métodos para iterar sobre matrices (como
forEach()
) con ciclos. Lo mismo ocurre con los programadores más avanzados cuando se comparan operador e instrucción ternariosif
.
La propuesta de do-expresión , actualmente en fase de negociación 1, tiene como objetivo mejorar aún más las capacidades de las expresiones JS. Y, por cierto, no confunda el concepto de "do-expresión" con bucles
do…while
, ya que son cosas completamente diferentes.
He aquí un ejemplo:
let x = do {
if (foo()) {
f();
} else if (bar()) {
g();
} else {
h();
}
};
Aquí está la sintaxis de la cláusula do-expression. En general, tenemos ante nosotros un fragmento de código JS envuelto en una construcción
do {}
. La última expresión de esta construcción se "devuelve" como el valor final de toda la expresión do.
Se puede lograr un efecto similar (pero no idéntico) utilizando un IIFE (Expresión de función invocada inmediatamente). Pero en el caso de las expresiones do, su sintaxis compacta parece muy atractiva. Aquí, con una funcionalidad similar, no necesita
return
ninguna estructura auxiliar fea como(() => {})()
... Es por eso que creo que una vez que las expresiones ingresen al estándar, su impacto en JavaScript será comparable al de las funciones de flecha. La conveniencia de las expresiones y la sintaxis amigable, por así decirlo, en un paquete, parecen muy tentadoras.
La coincidencia de patrones
Esta oportunidad es la última en este material, pero está lejos de ser la última en importancia. Se trata de una propuesta destinada a introducir un mecanismo de coincidencia de patrones en el lenguaje .
Puede que esté familiarizado con la instrucción JS
switch
. Es similar a if-else
, pero sus opciones son un poco más limitadas, y ciertamente es más adecuado para organizar la elección de una de las muchas alternativas. Así es como se ve:
switch (value) {
case 1:
// ...
break;
case 2:
// ...
break;
case 3:
// ...
break;
default:
// ...
break;
}
Personalmente, creo que una instrucción es
switch
más débil que una instrucción if
, ya que switch
puede comparar lo que se le pasa solo con valores específicos. Esta limitación se puede eludir , pero no sé por qué. Además, la instrucción está switch
sobrecargada con elementos auxiliares. En particular, estamos hablando de instrucciones break
.
El mecanismo de coincidencia de patrones se puede considerar como una versión más funcional, basada en expresiones y potencialmente más versátil de una declaración
switch
. En lugar de simplemente comparar valores, el mecanismo de coincidencia de patrones permite al desarrollador comparar valores con patrones personalizados (plantillas) que son altamente personalizables. Aquí hay un fragmento de código que muestra un ejemplo de la API propuesta:
const getLength = vector => case (vector) {
when { x, y, z } -> Math.hypot(x, y, z)
when { x, y } -> Math.hypot(x, y)
when [...etc] -> vector.length
}
getLength({x: 1, y: 2, z: 3})
Utiliza una sintaxis bastante inusual para JavaScript (aunque se basa en la sintaxis que se encuentra en lenguajes como Rust o Scala ), que tiene algunas similitudes con la instrucción que ya conocemos
switch
. Aquí, en lugar de una palabra clave, switch
se utiliza una palabra case
que marca el comienzo del bloque en el que se comprueba el valor. Luego, dentro del bloque, usando la palabra clavewhen
, describimos las plantillas con las que queremos validar valores. La sintaxis de las plantillas se asemeja a la sintaxis del mecanismo de desestructuración de objetos ya disponible en el lenguaje. Los valores se pueden comparar con objetos que contienen propiedades seleccionadas, se pueden comparar con valores de propiedad de objetos y con muchas otras entidades. Para obtener más información sobre este mecanismo, consulte este documento.
Después de la descripción de la plantilla, hay una flecha ("flecha plana"
->
) que apunta a la expresión (en perspectiva, incluso a un valor diferente), que debe evaluarse al encontrar una coincidencia con el patrón.
Creo que la presencia de tales capacidades en JS nos permitirá escribir, por así decirlo, código de nueva generación. Sin embargo, la sintaxis propuesta ahora me parece un poco engorrosa, ya que introduce muchas construcciones completamente nuevas en el lenguaje. Y el hecho de que esta propuesta se encuentre todavía en la 1ª fase de acuerdo me hace pensar que todavía tiene margen de mejora. Esta característica parece muy prometedora, pero aún queda un largo camino por recorrer antes de que se convierta en la especificación oficial de JS.
Salir
Con esto concluye mi historia sobre las características revolucionarias de JavaScript, que podemos ver en el lenguaje en el futuro. Existen otras posibilidades similares, por ejemplo, propuestas para una biblioteca estándar externa y un operador de canalización . Pero elegí para este material solo lo que me pareció más interesante. Tenga en cuenta que estas oportunidades aún se encuentran en la etapa de propuesta. Pueden cambiar con el tiempo. O puede suceder que nunca entren en el estándar. Pero si tú, en cualquier caso, quieres estar entre los que aprovechan estas oportunidades antes que otros, te aconsejo que eches un vistazo más de cerca a proyectos como Babel.... Estos proyectos dan origen a muchas oraciones JS (especialmente las relacionadas con la sintaxis). Esto permite que cualquiera pueda experimentar con las últimas funciones mucho antes de que aparezcan en las implementaciones del lenguaje.
¿Qué características extrañas más de JavaScript?