JavaScript es un lenguaje complejo. Si es un desarrollador de JavaScript en cualquier nivel, es importante comprender sus conceptos fundamentales. Este artículo aborda 12 conceptos que son fundamentales para que cualquier desarrollador de JS los entienda, pero de ninguna manera representa la amplitud completa de lo que un desarrollador de JS debe saber.
Nota: si te gusta este artículo, dale un aplauso 👏 (¡o 50!) para ayudar a correr la voz.
Actualizaré continuamente esta lista en un repositorio de Github llamado JS Tips & Tidbits . ¡Estrella ⭐ y comparte si quieres seguirnos!
Comprender cómo se asigna JavaScript a las variables es fundamental para escribir JavaScript sin errores. Si no entiende esto, podría escribir fácilmente un código que cambie los valores sin querer.
JavaScript siempre asigna variables por valor. Pero esta parte es muy importante: cuando el valor asignado es uno de los cinco tipos primitivos de JavaScript (es decir, Boolean
, null
, undefined
, String
y Number
), se asigna el valor real. Sin embargo, cuando el valor asignado es una Array
, una Function
o un Object
, se asigna una referencia al objeto en la memoria .
Tiempo de ejemplo! En el siguiente fragmento, var2
se establece como igual a var1
. Dado que var1
es un tipo primitivo ( String
), var2
se establece como igual al valor String
de var1
y se puede considerar como completamente distinto de var1
en este punto. En consecuencia, la reasignación de var2
no tiene efecto en var1.
let var1 = 'Mi cadena';let var2 = var1;
var2 = 'Mi nueva cadena';
console.log(var1);// 'Mi cadena'console.log(var2);// 'Mi nueva cadena'
Comparemos esto con la asignación de objetos.
let var1 = { nombre: 'Jim' }let var2 = var1;
var2.nombre = 'Juan';
consola.log(var1);// { nombre: 'Juan' }console.log(var2);// { nombre: 'Juan' }
¡Uno podría ver cómo esto podría causar problemas si esperaba un comportamiento como una asignación primitiva! Esto puede ponerse especialmente feo si crea una función que muta involuntariamente un objeto.
El cierre es un patrón de JavaScript importante para dar acceso privado a una variable. En este ejemplo, createGreeter
devuelve una función anónima que tiene acceso al greeting
proporcionado, "Hola". Para todos los usos futuros, sayHello
tendrá acceso a este saludo.
function createGreeter(saludo) {return función(nombre) {console.log(saludo + ', ' + nombre);}}
const decirHola = createGreeter('Hola');decirHola('Joe');// Hola, Joe
En un escenario más real, podría imaginar una función inicial apiConnect(apiKey)
que devuelve algunos métodos que usarían la clave API. En este caso, la apiKey
solo tendría que proporcionarse una vez y nunca más.
function apiConnect(apiKey) {function get(ruta) {return fetch(`${ruta}?key=${apiKey}`);}
function post(ruta, parámetros) {return fetch(ruta, { method: 'POST', body: JSON.stringify(params), headers: { 'Authorization': `Bearer ${apiKey}` } }
)}
volver {obtener, publicar}}
const api = apiConnect('mi-clave-secreta');
// Ya no es necesario incluir apiKeyapi.get('http://www.example.com/get-endpoint');api.post('http://www.example.com/post-endpoint', { nombre: 'Joe' });
¡No se deje intimidar por la desestructuración de parámetros de JavaScript! Es una forma común de extraer limpiamente las propiedades de los objetos.
const obj = {nombre: 'Joe',comida: 'pastel'}
const { nombre, alimento } = obj;
console.log(nombre, comida);// 'Joe' 'pastel'
Si desea extraer propiedades con un nombre diferente, puede especificarlas usando el siguiente formato.
const obj = {nombre: 'Joe',comida: 'pastel'}
const { nombre: miNombre, comida: miComida } = obj;
console.log(miNombre, miComida);// 'Joe' 'pastel'
En el siguiente ejemplo, se utiliza la desestructuración para pasar limpiamente el objeto person
a la función de introduce
. En otras palabras, la desestructuración puede usarse (y a menudo se usa) directamente para extraer parámetros pasados a una función. Si está familiarizado con React, ¡probablemente haya visto esto antes!
persona constante = {nombre: 'Eddie', edad: 24}
función presentar ({nombre, edad}) {console.log(`Soy ${nombre} y tengo ${edad} años!`);}
console.log(presente(persona));// "¡Soy Eddie y tengo 24 años!"
¡Un concepto de JavaScript que puede desconcertar a la gente pero que es relativamente simple es el operador de propagación! En el siguiente caso, Math.max
no se puede aplicar a la matriz arr
porque no toma una matriz como argumento, toma los elementos individuales como argumentos. El operador de propagación ...
se utiliza para sacar los elementos individuales de la matriz.
const arr = [4, 6, -1, 3, 10, 4];const max = Math.max(...arr);console.log(max);// 10
Hablemos de la sintaxis de descanso de JavaScript. ¡Puede usarlo para poner cualquier número de argumentos pasados a una función en una matriz!
function myFunc(...argumentos) {console.log(argumentos[0] + argumentos[1]);}
miFunc(1, 2, 3, 4);// 3
Los métodos de matriz de JavaScript a menudo pueden proporcionarle formas increíbles y elegantes de realizar la transformación de datos que necesita. Como colaborador de StackOverflow, con frecuencia veo preguntas sobre cómo manipular una matriz de objetos de una forma u otra. Este tiende a ser el caso de uso perfecto para los métodos de matriz.
Cubriré una serie de métodos de matriz diferentes aquí, organizados por métodos similares que a veces se combinan. Esta lista no es exhaustiva: lo animo a revisar y practicar todos los discutidos en MDN (mi referencia de JavaScript favorita).
** mapear, filtrar, reducir ** Existe cierta confusión en torno a los métodos de matriz de JavaScript map
, filter
, reduce
. Estos son métodos útiles para transformar una matriz o devolver un valor agregado.
const arr = [1, 2, 3, 4, 5, 6];const mapeado = arr.map(el => el + 20);
console.log(asignado);// [21, 22, 23, 24, 25, 26]
const arr = [1, 2, 3, 4, 5, 6];const filtered = arr.filter(el => el === 2 || el === 4);
console.log(filtrado);// [2, 4]
const arr = [1, 2, 3, 4, 5, 6];const reducido = arr.reduce((total, actual) => total + actual);
console.log(reducido);// 21
**find, findIndex, indexOf**Los métodos de matriz find
, findIndex
e indexOf
a menudo se pueden combinar. Úselos de la siguiente manera.
const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];const encontrado = arr.find(el => el > 5);
consola.log(encontrado);// 6
Nuevamente, tenga en cuenta que si bien todo lo que está después 5
cumple con los criterios, solo se devuelve el primer elemento coincidente. ¡Esto es realmente muy útil en situaciones en las que normalmente break
un bucle for cuando encuentras una coincidencia!
find
, pero en lugar de devolver el primer elemento coincidente, devuelve el índice del primer elemento coincidente. Tome el siguiente ejemplo, que usa nombres en lugar de números para mayor claridad.
const arr = ['Nick', 'Frank', 'Joe', 'Frank'];const foundIndex = arr.findIndex(el => el === 'Frank');
consola.log(índice encontrado);// 1
findIndex
, pero en lugar de tomar una función como argumento, toma un valor simple. Puede usar esto cuando tiene una lógica más simple y no necesita usar una función para verificar si hay una coincidencia.
const arr = ['Nick', 'Frank', 'Joe', 'Frank'];const foundIndex = arr.indexOf('Frank');
consola.log(índice encontrado);// 1
**push, pop, shift, unshift** Hay una gran cantidad de excelentes métodos de matriz para ayudar a agregar o eliminar elementos de las matrices de manera específica.
let arr = [1, 2, 3, 4];const empujado = arr.push(5);
console.log(arr);// [1, 2, 3, 4, 5]console.log(empujado);// 5
let arr = [1, 2, 3, 4];const popped = arr.pop();
console.log(arr);// [1, 2, 3]console.log(aparecido);// 4
let arr = [1, 2, 3, 4];const shifted = arr.shift();
consola.log(arr);// [2, 3, 4]console.log(cambiado);// 1
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(sin cambios);// 7
**empalme, corte**Estos métodos modifican o devuelven subconjuntos de matrices.
El siguiente ejemplo de código se puede leer como: en la posición 1
de la matriz, elimine 0
elementos e inserte b
.
let arr = ['a', 'c', 'd', 'e'];arr.splice(1, 0, 'b')
let arr = ['a', 'b', 'c', 'd', 'e'];const rebanada = arr.slice(2, 4);
consola.log(cortado);// ['c', 'd']console.log(arr);// ['a', 'b', 'c', 'd', 'e']
clasificar
let arr = [1, 7, 3, -1, 5, 7, 2];const sorter = (firstEl, secondEl) => firstEl - secondEl;arr.sort(sorter);
consola.log(arr);// [-1, 1, 2, 3, 5, 7, 7]
Uf, ¿captaste todo eso? Yo tampoco. De hecho, tuve que consultar mucho los documentos de MDN mientras escribía esto, ¡y está bien! El simple hecho de saber qué tipo de métodos existen te lleva al 95% del camino.
No temas el *
. La función del generador especifica qué value
se obtiene la próxima vez que se llama a next()
. Puede tener un número finito de rendimientos, después de lo cual next()
devuelve un value
indefinido, o un número infinito de valores mediante un bucle.
function* saludador() {yield 'Hola';yield '¿Cómo estás?';yield 'Adiós';}
const saludo = saludador();
console.log(saludar.siguiente().valor);// 'Hola'console.log(saludar.siguiente().valor);// '¿Cómo estás?'console.log(saludar.siguiente().valor );// 'Adiós'console.log(saludo.siguiente().valor);// indefinido
Y usando un generador para valores infinitos:
function* idCreator() {let i = 0;while (true)yield i++;}
const ids = idCreator();
console.log(ids.next().value);// 0console.log(ids.next().value);// 1console.log(ids.next().value);// 2// etc. ..
===
) vs. Operador de Igualdad ( ==
) ¡Asegúrese de conocer la diferencia entre el operador de identificación ( ===
) y el operador de igualdad ( ==
) en JavaScript! El operador ==
realizará la conversión de tipo antes de comparar valores, mientras que el operador ===
no realizará ninguna conversión de tipo antes de comparar.
consola.log(0 == '0');// trueconsole.log(0 === '0');// falso
Un error que veo que cometen los recién llegados a JavaScript es comparar objetos directamente. ¡Las variables apuntan a referencias a los objetos en la memoria, no a los objetos mismos! Un método para compararlos realmente es convertir los objetos en cadenas JSON. Sin embargo, esto tiene un inconveniente: ¡el orden de las propiedades de los objetos no está garantizado! Una forma más segura de comparar objetos es obtener una biblioteca que se especialice en la comparación profunda de objetos (por ejemplo, isEqual de lodash ).
Los siguientes objetos parecen iguales, pero de hecho apuntan a diferentes referencias.
const joe1 = { nombre: 'Joe' }; const joe2 = { nombre: 'Joe' };
consola.log(joe1 === joe2);// falso
Por el contrario, lo siguiente se evalúa como verdadero porque un objeto se establece igual que el otro objeto y, por lo tanto, apunta a la misma referencia (solo hay un objeto en la memoria).
const joe1 = { nombre: 'Joe' };const joe2 = joe1;
consola.log(joe1 === joe2);// verdadero
¡Asegúrese de revisar la sección Valor versus referencia anterior para comprender completamente las ramificaciones de establecer una variable igual a otra variable que apunta a una referencia a un objeto en la memoria!
¡Demasiadas personas se sienten intimidadas por las funciones de devolución de llamada de JavaScript! Son simples, toma este ejemplo. La función console.log
se pasa como devolución de llamada a myFunc
. Se ejecuta cuando se completa setTimeout
. ¡Eso es todo al respecto!
function myFunc(texto, devolución de llamada) {setTimeout(función() {devolución de llamada(texto);}, 2000);}
myFunc('¡Hola mundo!', console.log);// '¡Hola mundo!'
Una vez que comprenda las devoluciones de llamada de JavaScript, pronto se encontrará en un "infierno de devolución de llamada" anidado. ¡Aquí es donde Promises ayuda! Envuelva su lógica asíncrona en una Promesa y resolve
si tiene éxito o reject
si falla. Use "then" para manejar el éxito y catch
para manejar el fracaso.
const myPromise = new Promise(function(res, rej) {setTimeout(function(){if (Math.random() < 0.9) {return res('¡Hurra!');}return rej('¡Oh, no!'); }, 1000);});
myPromise.then(función(datos) {console.log('Éxito: ' + datos);}).catch(función(err) {console.log('Error: ' + err);});
// Si Math.random() devuelve menos de 0,9, se registra lo siguiente: // "Éxito: ¡Hurra!"// Si Math.random() devuelve 0,9 o más, se registra lo siguiente: // "Error: ¡No! "
Una vez que aprenda las promesas de JavaScript, es posible que le guste async await
, que es simplemente "azúcar sintáctico" además de las promesas. En el siguiente ejemplo, creamos una función async
y dentro de ella await
la promesa de greeter
.
const saludador = new Promise((res, rej) => {setTimeout(() => res('¡Hola mundo!'), 2000);})
función asíncrona myFunc() {const saludo = esperar saludo;console.log(saludo);}
myFunc();// '¡Hola mundo!'
Si no conocía ninguno de estos 12 conceptos, es probable que haya crecido al menos un poco en su conocimiento de JavaScript. Y si los conocía a todos, espero que esta sea una oportunidad para practicar y aumentar su conocimiento. ¿Qué otros conceptos crees que son críticos? Házmelo saber en los comentarios.