12 conceptos de JavaScript para conocer

JavaScript es un lenguaje complejo. Si usted, en cualquier nivel, participa en el desarrollo de JavaScript, esto significa que es vital que comprenda los conceptos básicos de este lenguaje. El material, cuya traducción publicamos hoy, cubre 12 conceptos críticos de JavaScript. Por supuesto, el desarrollador de JavaScript necesita saber mucho más, pero sin lo que vamos a hablar hoy, definitivamente no puede hacerlo.



1. Variables que almacenan valores y referencias


Comprender cómo se asignan exactamente los valores variables en JavaScript es extremadamente importante para aquellos que desean escribir correctamente el código de trabajo. El malentendido de este mecanismo lleva a escribir programas en los que los valores de las variables pueden cambiar inadvertidamente.

JavaScript, si una entidad tiene uno de los tipos primitivos (en particular, los tipos Boolean , null , undefined , de String y Number ), siempre funciona con el valor de esta entidad. Es decir, el valor se escribe en la variable correspondiente. Si estamos hablando de un objeto (por ejemplo, los tipos Object , Array , Function ), al asignarlo a una variable, se le escribe una referencia, la dirección en la que se encuentra en la memoria.

Considera un ejemplo. En el siguiente fragmento de código, se escribe una cadena en var1 . Después de eso, el valor de var2 escribe en la variable var2 . Dado que la variable var1 tiene un tipo primitivo ( String ), se escribirá una copia de la cadena disponible en var1 en var1 . Esto nos permite considerar var2 como una variable que es completamente independiente de var1 , aunque almacena el mismo valor que var1 . Escribir un nuevo valor en var1 no afecta a var1 .

 let var1 = 'My string'; let var2 = var1; var2 = 'My new string'; console.log(var1); // 'My string' console.log(var2); // 'My new string' 

Ahora considere un ejemplo de trabajo con objetos.

 let var1 = { name: 'Jim' } let var2 = var1; var2.name = 'John'; console.log(var1); // { name: 'John' } console.log(var2); // { name: 'John' } 

Como puede ver, aquí estamos trabajando con la variable var2 , y lo que le sucede se refleja en la variable var1 , ya que almacenan una referencia al mismo objeto. Es fácil imaginar a qué puede conducir esto en código real si alguien decide que las variables que almacenan objetos se comportan de la misma manera que las variables que almacenan valores de tipos primitivos. Esto es especialmente desagradable, por ejemplo, en los casos en que crean una función que está diseñada para funcionar con el valor del objeto que se le pasa, y esta función cambia inadvertidamente este valor.

2. Cortocircuitos


El cierre es un patrón de diseño importante en JavaScript que le permite organizar el trabajo protegido con variables. En el siguiente ejemplo, la función createGreeter() devuelve una función anónima que tiene acceso al argumento original proporcionado con el argumento de greeting que contiene la cadena Hello . Se escribe una referencia a esta función anónima en la variable sayHello . Después de eso, no importa cuántas veces llamemos a la función sayHello() , siempre tendrá acceso al valor de greeting . En este caso, el acceso al greeting solo será una función anónima, un enlace que se registra en sayHello .

 function createGreeter(greeting) { return function(name) {   console.log(greeting + ', ' + name); } } const sayHello = createGreeter('Hello'); sayHello('Joe'); // Hello, Joe 

Este fue un ejemplo muy simple. Si miramos algo más cercano al mundo real, podemos imaginar, por ejemplo, una función para conectarse a una determinada API (llamémosla apiConnect() ), que, cuando se llama por primera vez, se le pasa una clave de acceso a la API. Esta función, a su vez, devuelve un objeto que contiene varios métodos que usan la clave de acceso a la API que se pasó a apiConnect() . En este caso, la clave se almacena en el cierre y cuando llama a estos métodos, ya no es necesario mencionarla.

 function apiConnect(apiKey) { function get(route) {   return fetch(`${route}?key=${apiKey}`); } function post(route, params) {   return fetch(route, {     method: 'POST',     body: JSON.stringify(params),       headers: {         'Authorization': `Bearer ${apiKey}`       }     }) } return { get, post } } const api = apiConnect('my-secret-key'); //     API     api.get('http://www.example.com/get-endpoint'); api.post('http://www.example.com/post-endpoint', { name: 'Joe' }); 

3. Asignación destructiva


Si aún no ha utilizado la asignación destructiva en JavaScript, entonces es hora de arreglarlo. La asignación destructiva es una forma común de recuperar propiedades de objetos utilizando una construcción de lenguaje sintáctico ordenado.

 const obj = { name: 'Joe', food: 'cake' } const { name, food } = obj; console.log(name, food); // 'Joe' 'cake' 

Si necesita asignar los nombres de propiedades extraídos que son diferentes de los que tienen en el objeto, puede hacer esto:

 const obj = { name: 'Joe', food: 'cake' } const { name: myName, food: myFood } = obj; console.log(myName, myFood); // 'Joe' 'cake' 

En el siguiente ejemplo, la desestructuración se utiliza para pasar con precisión los valores almacenados en las propiedades del objeto person a la función de introduce() . Este es un ejemplo de cómo se usa esta construcción cuando se declara una función para recuperar datos de un objeto con parámetros que se le pasan. Por cierto, si estás familiarizado con React, entonces probablemente ya lo hayas visto.

 const person = { name: 'Eddie', age: 24 } function introduce({ name, age }) { console.log(`I'm ${name} and I'm ${age} years old!`); } console.log(introduce(person)); // "I'm Eddie and I'm 24 years old!" 

4. El operador de propagación


El operador de propagación es una construcción bastante simple que puede parecer incomprensible para una persona no preparada. El siguiente ejemplo tiene una matriz numérica, el valor máximo almacenado en el que necesitamos encontrar. Queremos usar el método Math.max() para esto, pero no sabe cómo trabajar con matrices. Él, como argumentos, asume valores numéricos independientes. Para extraer sus elementos de la matriz, utilizamos el operador de propagación, que se parece a tres puntos.

 const arr = [4, 6, -1, 3, 10, 4]; const max = Math.max(...arr); console.log(max); // 10 

5. La declaración de descanso


El operador rest le permite convertir cualquier número de argumentos pasados ​​a una función en una matriz.

 function myFunc(...args) { console.log(args[0] + args[1]); } myFunc(1, 2, 3, 4); // 3 

6. Métodos de matriz


Los métodos de matriz a menudo brindan al desarrollador herramientas convenientes para resolver bellamente una variedad de tareas de conversión de datos. A veces respondo preguntas en StackOverflow. Entre ellos, a menudo hay aquellos que se dedican a algo como esas u otras formas de trabajar con matrices de objetos. Es en tales situaciones que los métodos de matriz son especialmente útiles.

Aquí consideraremos varios de estos métodos, unidos por el principio de su similitud entre sí. Cabe señalar que aquí no le contaré sobre todos los métodos de matrices. Puede encontrar su lista completa en MDN (por cierto, esta es mi referencia de JavaScript favorita).

Métodos apMap (), filter () y reduce ()


Los métodos de matriz map() , filter() y reduce() permiten transformar matrices o reducir matrices a un solo valor (que puede ser un objeto).

El método map() devuelve una nueva matriz que contiene los valores transformados de la matriz procesada. La forma exacta en que se transformarán se especifica en la función que se pasa a este método.

 const arr = [1, 2, 3, 4, 5, 6]; const mapped = arr.map(el => el + 20); console.log(mapped); // [21, 22, 23, 24, 25, 26] 

El método filter() devuelve una matriz de elementos, verificando los valores de los cuales la función pasada a este método devuelve true .

 const arr = [1, 2, 3, 4, 5, 6]; const filtered = arr.filter(el => el === 2 || el === 4); console.log(filtered); // [2, 4] 

El método reduce() devuelve un cierto valor, que es el resultado del procesamiento de todos los elementos de la matriz.

 const arr = [1, 2, 3, 4, 5, 6]; const reduced = arr.reduce((total, current) => total + current); console.log(reduced); // 21 

▍ Métodos find (), findIndex () e indexOf ()


Los métodos de matriz find() , findIndex() e indexOf() fáciles de confundir entre sí. Las siguientes son explicaciones para ayudarlo a comprender sus características.

El método find() devuelve el primer elemento de la matriz que coincide con los criterios especificados. Este método, al encontrar el primer elemento adecuado, no continúa la búsqueda en la matriz.

 const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; const found = arr.find(el => el > 5); console.log(found); // 6 

Tenga en cuenta que en nuestro ejemplo, los criterios dados corresponden a todos los elementos de la matriz que siguen al que contiene el número 5, pero solo se devuelve el primer elemento adecuado. Este método es muy útil en situaciones en las que, al usar los bucles for para enumerar y analizar matrices, dichos bucles se interrumpen cuando se encuentra el elemento deseado en la matriz, utilizando la instrucción break .

El método findIndex() es muy similar a find() , pero en lugar de devolver el primer elemento adecuado en la matriz, devuelve el índice de ese elemento. Para comprender mejor este método, eche un vistazo al siguiente ejemplo, que utiliza una matriz de valores de cadena.

 const arr = ['Nick', 'Frank', 'Joe', 'Frank']; const foundIndex = arr.findIndex(el => el === 'Frank'); console.log(foundIndex); // 1 

El método indexOf() es muy similar al método findIndex() , pero toma como argumento no una función, sino un valor normal. Se puede usar si no se necesita una lógica compleja al buscar el elemento de matriz deseado.

 const arr = ['Nick', 'Frank', 'Joe', 'Frank']; const foundIndex = arr.indexOf('Frank'); console.log(foundIndex); // 1 

▍ Métodos Push (), pop (), shift () y unshift ()


Los unshift() push() , pop() , shift() y unshift() se utilizan para agregar nuevos elementos a las matrices y extraer elementos que ya existen en ellas. En este caso, el trabajo se realiza con elementos ubicados al principio o al final de la matriz.

El método push() permite agregar elementos al final de una matriz. Modifica la matriz y, al finalizar, devuelve el elemento agregado a la matriz.

 let arr = [1, 2, 3, 4]; const pushed = arr.push(5); console.log(arr); // [1, 2, 3, 4, 5] console.log(pushed); // 5 

El método pop() elimina el último elemento de la matriz. Modifica la matriz y devuelve el elemento eliminado de ella.

 let arr = [1, 2, 3, 4]; const popped = arr.pop(); console.log(arr); // [1, 2, 3] console.log(popped); // 4 

El método shift() elimina el primer elemento de la matriz y lo devuelve. También modifica la matriz para la que se llama.

 let arr = [1, 2, 3, 4]; const shifted = arr.shift(); console.log(arr); // [2, 3, 4] console.log(shifted); // 1 

El método unshift() agrega uno o más elementos al comienzo de una matriz. Él, nuevamente, modifica la matriz. Al mismo tiempo, a diferencia de los otros tres métodos discutidos aquí, devuelve la nueva longitud de la matriz.

 let arr = [1, 2, 3, 4]; const unshifted = arr.unshift(5, 6, 7); console.log(arr); // [5, 6, 7, 1, 2, 3, 4] console.log(unshifted); // 7 

Métodos liceSlice () y splice ()


Estos métodos se utilizan para modificar la matriz o para devolver alguna parte de la matriz.

El método splice() cambia el contenido de una matriz eliminando elementos existentes o reemplazándolos con otros elementos. Es capaz de agregar nuevos elementos a la matriz. Este método modifica la matriz.

El siguiente ejemplo, si lo describe en un lenguaje ordinario, se ve así: necesita, en la posición de matriz 1 , eliminar 0 elementos y agregar un elemento que contenga b .

 let arr = ['a', 'c', 'd', 'e']; arr.splice(1, 0, 'b') 

El método slice() devuelve una copia superficial de la matriz que contiene sus elementos, comenzando desde la posición inicial dada y terminando con la posición que precede a la posición final dada. Si, al llamarlo, solo se especifica la posición inicial, entonces devolverá toda la matriz, comenzando desde esta posición. Este método no modifica la matriz. Solo devuelve la parte de esta matriz descrita cuando se llamó.

 let arr = ['a', 'b', 'c', 'd', 'e']; const sliced = arr.slice(2, 4); console.log(sliced); // ['c', 'd'] console.log(arr); // ['a', 'b', 'c', 'd', 'e'] 

▍ Método sort ()


El método sort() clasifica la matriz de acuerdo con la condición especificada por la función que se le pasa. Esta función toma dos elementos de la matriz (por ejemplo, se pueden representar como parámetros a y b ) y, comparándolos, devuelve, si los elementos no necesitan intercambiarse, 0 si necesita colocarse en un índice más bajo que b es un número negativo, y si b necesita ponerse en un índice más bajo que a es un número positivo.

 let arr = [1, 7, 3, -1, 5, 7, 2]; const sorter = (firstEl, secondEl) => firstEl - secondEl; arr.sort(sorter); console.log(arr); // [-1, 1, 2, 3, 5, 7, 7] 

Si no puede recordar estos métodos por primera vez, recordarlos está bien. Lo más importante es que ahora sabe lo que pueden hacer los métodos de matriz estándar. Por lo tanto, si no puede recordar de inmediato las características de un método en particular, lo que sepa sobre él le permitirá encontrar rápidamente lo que necesita en la documentación.

7. generadores


Los generadores de JavaScript se declaran con un asterisco. Le permiten especificar qué valor se devolverá la próxima vez que se llame al método next() . Los generadores pueden diseñarse para devolver un número limitado de valores. Si dicho generador devolvió todos esos valores, la siguiente llamada a next() regresará undefined . También puede crear generadores diseñados para devolver un número ilimitado de valores mediante ciclos.

Aquí hay un generador diseñado para devolver un número limitado de valores:

 function* greeter() { yield 'Hi'; yield 'How are you?'; yield 'Bye'; } const greet = greeter(); console.log(greet.next().value); // 'Hi' console.log(greet.next().value); // 'How are you?' console.log(greet.next().value); // 'Bye' console.log(greet.next().value); // undefined 

Y aquí hay un generador diseñado para devolver un número infinito de valores a través de un bucle.

 function* idCreator() { let i = 0; while (true)   yield i++; } const ids = idCreator(); console.log(ids.next().value); // 0 console.log(ids.next().value); // 1 console.log(ids.next().value); // 2 //   ... 

8. Operadores para verificar la igualdad (==) y la igualdad estricta (===) de valores


Es extremadamente importante para cualquier desarrollador de JS comprender la diferencia entre los operadores de igualdad ( == ) e igualdad estricta ( === ). El hecho es que el operador == , antes de comparar los valores, realiza la conversión de sus tipos (lo que puede conducir a extrañas, a primera vista, consecuencias), y el operador === no realiza la conversión de tipos.

 console.log(0 == '0'); // true console.log(0 === '0'); // false 

9. Comparación de objetos


De vez en cuando tengo que ver cómo los recién llegados a la programación JS cometen el mismo error. Intentan comparar objetos directamente. Las variables en las que los objetos están "almacenados" contienen referencias a ellos, y no estos objetos en sí.

Entonces, por ejemplo, en el siguiente ejemplo, los objetos se ven iguales, pero cuando se comparan directamente, se nos informa que los objetos son diferentes, ya que cada una de las variables contiene un enlace a su propio objeto y estos enlaces no son iguales entre sí.

 const joe1 = { name: 'Joe' }; const joe2 = { name: 'Joe' }; console.log(joe1 === joe2); // false 

Además, en el siguiente ejemplo, resulta que joe1 es igual a joe2 ya que ambas variables almacenan una referencia al mismo objeto.

 const joe1 = { name: 'Joe' }; const joe2 = joe1; console.log(joe1 === joe2); // true 

Uno de los métodos de comparación de objetos reales es su conversión preliminar al formato de cadena JSON. Es cierto que este enfoque tiene un problema, que es que en la representación de cadena obtenida del objeto no se garantiza un cierto orden de sus propiedades. Una forma más confiable de comparar objetos es usar una biblioteca especial que contenga herramientas para una comparación profunda de objetos (por ejemplo, este es el método isEqual () de la biblioteca lodash ).

Para comprender mejor las complejidades de comparar objetos y comprender las posibles consecuencias de escribir enlaces a los mismos objetos en diferentes variables, eche un vistazo al primer concepto JS discutido en este artículo.

10. Funciones de devolución de llamada


Las funciones de devolución de llamada son un concepto de JavaScript bastante simple con el que los novatos a veces tienen dificultades. Considere el siguiente ejemplo. Aquí, la función console.log (así como así, sin paréntesis) se pasa a myFunc() como una función de devolución de llamada. Esta función establece un temporizador, después del cual se llama a myFunc() y la cadena que se pasa a myFunc() se muestra en la consola.

 function myFunc(text, callback) { setTimeout(function() {   callback(text); }, 2000); } myFunc('Hello world!', console.log); // 'Hello world!' 

11. Promesas


Después de dominar las funciones de devolución de llamada y comenzar a usarlas en todas partes, pronto se encontrará en el llamado "infierno de devolución de llamada". Si realmente estás allí, mira las promesas. El código asincrónico se puede incluir en una promesa y, después de su ejecución exitosa, informar al sistema sobre la resolución exitosa de la promesa llamando al método apropiado y, si algo sale mal, llame al método que indica esto y rechace la promesa. Para procesar los resultados devueltos por la promesa, use el método then() , y para el manejo de errores, use el método catch() .

 const myPromise = new Promise(function(res, rej) { setTimeout(function(){   if (Math.random() < 0.9) {     return res('Hooray!');   }   return rej('Oh no!'); }, 1000); }); myPromise .then(function(data) {   console.log('Success: ' + data);  })  .catch(function(err) {   console.log('Error: ' + err);  }); //  Math.random()  , ,  0.9,    : // "Success: Hooray!" //  Math.random()  , ,  0.9,  0.9,    : // "Error: On no!" 

12. construcción asíncrona / espera


Después de trabajar con las promesas, entonces, posiblemente, querrás algo más. Por ejemplo, domine la construcción asíncrona / espera. Es azúcar sintáctico para promesas. En el siguiente ejemplo, creamos, usando la async , una función asincrónica, y en ella, usando la palabra clave wait, organizamos la espera para greeter bienvenida.

 const greeter = new Promise((res, rej) => { setTimeout(() => res('Hello world!'), 2000); }) async function myFunc() { const greeting = await greeter; console.log(greeting); } myFunc(); // 'Hello world!' 

Resumen


Si lo que hablamos aquí anteriormente no le era familiar, lo más probable es que, al menos un poco, haya crecido por encima de usted al leer este artículo. Si no ha encontrado nada nuevo aquí, me gustaría esperar que este material le brinde la oportunidad de practicar y fortalecer su conocimiento de JavaScript.

Estimados lectores! ¿Qué otros conceptos de JavaScript agregarías a este artículo?

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


All Articles