Innovaciones de literales de objetos en JavaScript ES6

El material, cuya traducción presentamos a su atención, está dedicado al estudio de las características de los literales de objetos en JavaScript, en particular, las innovaciones que aparecieron en versiones recientes del estándar ECMAScript.

JavaScript tiene una capacidad poderosa y conveniente para crear objetos usando literales de objeto. El estándar ES2015 (ES6) simplifica el trabajo con objetos al crear aplicaciones para navegadores modernos (excepto IE) y para la plataforma Node.js.



Los fundamentos


Crear objetos en algunos lenguajes puede requerir muchos recursos, por lo que nos referimos tanto al tiempo de trabajo del programador como a los recursos informáticos de los sistemas. En particular, estamos hablando del hecho de que antes de crear objetos, debe describir las clases (por ejemplo, usando la palabra clave class ). En JavaScript, los objetos se pueden crear de forma rápida y sencilla, sin necesidad de pasos preliminares. Considere un ejemplo:

 // ES5 var myObject = { prop1: 'hello', prop2: 'world', output: function() {   console.log(this.prop1 + ' ' + this.prop2); } }; myObject.output(); // hello world 

En la programación, a menudo se usan objetos "desechables". Almacenan configuraciones y otros datos, se usan como parámetros de funciones, como valores devueltos por funciones y en otras situaciones. Los literales de objetos de JavaScript en estos casos resultan muy útiles y ES6 amplía sus capacidades.

Inicialización de objetos a partir de variables.


Las propiedades de los objetos a menudo se crean a partir de variables asignándoles los mismos nombres que ya están asignados a estas variables. Por ejemplo:

 // ES5 var a = 1, b = 2, c = 3; obj = {   a: a,   b: b,   c: c }; // obj.a = 1, obj.b = 2, obj.c = 3 

En ES6, ya no necesita repetir nombres de variables:

 // ES6 const a = 1, b = 2, c = 3; obj = {   a,   b,   c }; // obj.a = 1, obj.b = 2, obj.c = 3 

Esta técnica puede ser útil para los objetos devueltos cuando se utiliza el patrón Revealing Module , que le permite crear espacios de nombres para varios fragmentos de código para evitar conflictos de nombres. Por ejemplo:

 // ES6 const lib = (() => { function sum(a, b)  { return a + b; } function mult(a, b) { return a * b; } return {   sum,   mult }; }()); console.log( lib.sum(2, 3) );  // 5 console.log( lib.mult(2, 3) ); // 6 

Es posible que haya visto cómo se usa esta técnica en los módulos ES6:

 // lib.js function sum(a, b)  { return a + b; } function mult(a, b) { return a * b; } export { sum, mult }; 

Sintaxis abreviada para declarar métodos de objetos


Al declarar métodos de objeto en ES5, debe usar la palabra clave de function :

 // ES5 var lib = { sum:  function(a, b) { return a + b; }, mult: function(a, b) { return a * b; } }; console.log( lib.sum(2, 3) );  // 5 console.log( lib.mult(2, 3) ); // 6 

Ahora, en ES6, ya no puede hacer esto. Aquí se permite la siguiente forma abreviada de declarar métodos:

 // ES6 const lib = { sum(a, b)  { return a + b; }, mult(a, b) { return a * b; } }; console.log( lib.sum(2, 3) );  // 5 console.log( lib.mult(2, 3) ); // 6 

Cabe señalar que las funciones de flecha ES6 ( => ) no se pueden usar aquí, ya que los métodos deben tener nombres. Sin embargo, las funciones de flecha se pueden usar si asigna nombres explícitamente a los métodos (como en ES5). Por ejemplo:

 // ES6 const lib = { sum:  (a, b) => a + b, mult: (a, b) => a * b }; console.log( lib.sum(2, 3) );  // 5 console.log( lib.mult(2, 3) ); // 6 

Claves dinámicas


En ES5, no podía usar variables como nombres de clave, aunque la clave cuyo nombre se le dio a la variable podría agregarse después de crear el objeto. Por ejemplo:

 // ES5 var key1 = 'one', obj = {   two: 2,   three: 3 }; obj[key1] = 1; // obj.one = 1, obj.two = 2, obj.three = 3 

En ES6, las claves se pueden asignar dinámicamente colocando una expresión de nombre entre corchetes ( [] ). Por ejemplo:

 // ES6 const key1 = 'one', obj = {   [key1]: 1,   two: 2,   three: 3 }; // obj.one = 1, obj.two = 2, obj.three = 3 

Para crear una clave, puede usar cualquier expresión:

 // ES6 const i = 1, obj = {   ['i' + i]: i }; console.log(obj.i1); // 1 

Las claves dinámicas se pueden usar tanto para métodos como para propiedades:

 // ES6 const i = 2, obj = {   ['mult' + i]: x => x * i }; console.log( obj.mult2(5) ); // 10 

Otra pregunta es si crear propiedades y métodos con nombres generados dinámicamente. La legibilidad del código que usa esta técnica puede verse degradada. Quizás si se enfrenta a situaciones en las que los nombres dinámicos parecen apropiados, sería mejor pensar en usar funciones de fábrica o clases para crear objetos.

Reestructuración


La desestructuración es la extracción de propiedades de objetos y su asignación a variables. A menudo, durante el desarrollo de la aplicación, debe extraer el valor de una propiedad de objeto y escribirlo en una variable. En ES5, tenía que describir esto de la siguiente manera, utilizando los comandos de acceso a la propiedad:

 // ES5 var myObject = { one:   'a', two:   'b', three: 'c' }; var one   = myObject.one, // 'a' two   = myObject.two, // 'b' three = myObject.three; // 'c' 

ES6 soporta la desestructuración. Puede crear una variable con el mismo nombre que lleve la propiedad correspondiente del objeto y hacer lo siguiente:

 // ES6 const myObject = { one:   'a', two:   'b', three: 'c' }; const { one, two, three } = myObject; // one = 'a', two = 'b', three = 'c' 

Las variables en las que caen los valores de las propiedades de los objetos pueden tener nombres, pero si difieren de los nombres de las propiedades, debe usar la { propertyName: newVariable } :

 // ES6 const myObject = { one:   'a', two:   'b', three: 'c' }; const { one: first, two: second, three: third } = myObject; // first = 'a', second = 'b', third = 'c' 

Los objetos con una estructura compleja, en la que se incorporan matrices y otros objetos, también se pueden usar en operaciones de asignación destructivas:

 // ES6 const meta = { title: 'Enhanced Object Literals', pageinfo: {   url: 'https://www.sitepoint.com/',   description: 'How to use object literals in ES2015 (ES6).',   keywords: 'javascript, object, literal' } }; const { title   : doc, pageinfo: { keywords: topic } } = meta; /* doc   = 'Enhanced Object Literals' topic = 'javascript, object, literal' */ 

Al principio, todo esto puede parecer complicado, sin embargo, no es tan difícil de resolver, lo principal es recordar lo siguiente:

  • El lado derecho de la expresión es la fuente de datos, una matriz u objeto que almacena los datos que se recuperarán.
  • El lado izquierdo de la expresión es el objetivo de la asignación destructiva, una estructura que describe las variables a las que se les asignarán los valores extraídos de la matriz u objeto.

Al utilizar la desestructuración, puede encontrar algunas dificultades. Por lo tanto, una expresión no se puede iniciar con una llave, porque entonces se verá como un bloque de código. Por ejemplo:

 { a, b, c } = myObject; //  

Este diseño es normalmente percibido por el sistema cuando declara variables:

 const { a, b, c } = myObject; //  

Si las variables ya están declaradas, debe encerrar la expresión entre paréntesis:

 let a, b, c; ({ a, b, c } = myObject); //  

Como resultado, cuando se trata de la desestructuración, debe tener cuidado con el código y no mezclar variables declaradas y no declaradas.

La desestructuración es una técnica que puede ser útil en muchas situaciones.

Parámetros de función predeterminados


Si una función necesita una larga lista de argumentos, generalmente es más fácil pasarle un solo objeto con parámetros. Por ejemplo:

 prettyPrint( { title: 'Enhanced Object Literals', publisher: {   name: 'SitePoint',   url: 'https://www.sitepoint.com/' } } ); 

En ES5, era necesario analizar objetos con parámetros para, si estos objetos no tienen lo que necesitan, asignar valores predeterminados a los parámetros correspondientes:

 // ES5,     function prettyPrint(param) { param = param || {}; var   pubTitle = param.title || 'No title',   pubName = (param.publisher && param.publisher.name) || 'No publisher'; return pubTitle + ', ' + pubName; } 

En ES6, a cualquier parámetro se le pueden asignar valores predeterminados:

 // ES6 -     function prettyPrint(param = {}) { ... } 

Luego puede usar la desestructuración para extraer valores del objeto y, si es necesario, asignar valores predeterminados:

 // ES6     function prettyPrint( {   title: pubTitle = 'No title',   publisher: { name: pubName = 'No publisher' } } = {} ) { return `${pubTitle}, ${pubName}`; } 

Vale la pena señalar que dicho código puede ser más difícil de leer que el más tradicional, aunque esto es una cuestión de preferencias personales del programador.

Analizando objetos devueltos por funciones


Las funciones pueden devolver solo un valor, pero este valor puede ser un objeto con cientos de propiedades o métodos. En ES5, primero tenía que obtener el objeto devuelto, y luego podía extraer los valores de él:

 // ES5 var obj = getObject(), one = obj.one, two = obj.two, three = obj.three; 

La reestructuración simplifica este proceso. Ahora todo esto se puede hacer sin tener que guardar el objeto en una variable separada y luego analizarlo:

 // ES6 const { one, two, three } = getObject(); 

Es posible que haya visto algo similar en Node.js. Por ejemplo, si solo necesita los readFile() y writeFile() del módulo fs , puede obtener enlaces a ellos de esta manera:

 // ES6 Node.js const { readFile, writeFile } = require('fs'); readFile('file.txt', (err, data) => { console.log(err || data); }); writeFile('new.txt', 'new content', err => { console.log(err || 'file written'); }); 

Sintaxis de parámetro restante y operador de extensión ES2018 (ES9)


= En ES2015, la sintaxis de los parámetros restantes y el operador de extensión (ambos parecen tres puntos, ) se usaron solo cuando se trabajaba con matrices. En ES2018, se puede utilizar una funcionalidad similar para trabajar con objetos:

 const myObject = { a: 1, b: 2, c: 3 }; const { a, ...x } = myObject; // a = 1 // x = { b: 2, c: 3 } 

Se puede usar un enfoque similar para transferir ciertos valores a una función:

 function restParam({ a, ...x }) { // a = 1 // x = { b: 2, c: 3 } } restParam({ a: 1, b: 2, c: 3 }); 

Tenga en cuenta que en tales situaciones, puede usar solo una expresión con tres puntos al final de la lista. Además, para objetos anidados en otros objetos, esto no funciona.

El operador de extensión se puede usar dentro de objetos:

 const obj1 = { a: 1, b: 2, c: 3 }, obj2 = { ...obj1, z: 26 }; // obj2 is { a: 1, b: 2, c: 3, z: 26 } 

El operador de extensión se puede utilizar para clonar objetos ( obj2 = { ...obj1 }; ), pero aquí debe tenerse en cuenta que con este enfoque, se realiza una copia superficial del objeto. Si las propiedades de los objetos son otros objetos, el clon del objeto se referirá a los mismos objetos anidados.

La sintaxis de los parámetros restantes y el operador de extensión aún no son ampliamente compatibles. Actualmente, se pueden usar en los navegadores Chrome y Firefox sin esfuerzos adicionales, y cuando se desarrollan para la plataforma Node.js versión 8.6 y superior.

Resumen


Los literales de objeto siempre han sido una característica útil de JavaScript. Las innovaciones que aparecen en JavaScript desde el estándar ES2015 no traen cambios fundamentales, pero ahorran el tiempo del programador y ayudan a escribir código más limpio y conciso.

Estimados lectores! ¿Qué métodos de creación de objetos JS usas con más frecuencia?

Source: https://habr.com/ru/post/es414377/


All Articles