Curso de ECMAScript: Historia y Versiones de JavaScript
18 |
19 |
20 | JavaScript es el lenguaje más utilizado para desarrollo de aplicaciones web, principalmente en el frontend. Cada año, ECMA International publica una nueva edición de ECMAScript, la especificación a la cual se ajusta JavaScript. Aprende las nuevas características que implementa ECMAScript desde la versión ES6 hasta la versión ES13
21 |
22 | Explore los documentos »
23 |
24 |
25 |
26 |
27 | ---
28 |
29 | ## Índice
30 |
31 | - [Índice](#índice)
32 | - [Introducción](#introducción)
33 | - [Historia de JavaScript: ¿Qué es ECMAScript?](#historia-de-javascript-¿qué-es-ecmascript)
34 | - [¿Qué es el TC39?](#¿qué-es-el-tc39)
35 | - [ECMAScript 6 (ES6 o ES2015)](#ecmascript-6-es6-o-es2015)
36 | - [Let y const, y arrow function](#let-y-const-y-arrow-function)
37 | - [Strings](#strings)
38 | - [Parámetros por defecto](#parámetros-por-defecto)
39 | - [Asignación de desestructuración](#asignación-de-desestructuración)
40 | - [Spread operator](#spread-operator)
41 | - [Object literals](#object-literals)
42 | - [Promesas](#promesas)
43 | - [Clases](#clases)
44 | - [Module](#module)
45 | - [Generator](#generator)
46 | - [Set-add](#set-add)
47 | - [ECMAScript 7 (ES7 o ES2016)](#ecmascript-7-es7-o-es2016)
48 | - [Operador de potenciación y array includes](#operador-de-potenciación-y-array-includes)
49 | - [ECMAScript 8 (ES8 o ES2017)](#ecmascript-8-es8-o-es2017)
50 | - [Object entries y object values](#object-entries-y-object-values)
51 | - [String padding y trailing commas](#string-padding-y-trailing-commas)
52 | - [Funciones asíncronas](#funciones-asíncronas)
53 | - [ECMAScript 9 (ES9 o ES2018)](#ecmascript-9-es9-o-es2018)
54 | - [Expresiones regulares](#expresiones-regulares)
55 | - [Promise.finally](#promisefinally)
56 | - [ECMAScript 10 (ES10 o ES2019)](#ecmascript-10-es10-o-es2019)
57 | - [Flat-map y trimStart-trimEnd](#flat-map-y-trimstart-trimend)
58 | - [Try catch y fromEntries](#try-catch-y-fromentries)
59 | - [ECMAScript 11 (ES11 o ES2020)](#ecmascript-11-es11-o-es2020)
60 | - [Optional chaining](#optional-chaining)
61 | - [BigInt y Nullish](#bigint-y-nullish)
62 | - [Promise.allSettled ](#promiseallsettled)
63 | - [GlobalThis y matchAll](#globalthis-y-matchall)
64 | - [Dynamic Import](#dynamic-import)
65 | - [ECMAScript 12 (ES12 o ES2021)](#ecmascript-12-es12-o-es2021)
66 | - [Numeric-separators y replaceAll](#numeric-separators-y-replaceall)
67 | - [Promise-any y métodos privados](#promise-any-y-métodos-privados)
68 | - [ECMAScript 13 (ES13 o ES2022)](#ecmascript-13-es13-o-es2022)
69 | - [At](#at)
70 | - [Top level await en el consumo de una API](#top-level-await-en-el-consumo-de-una-api)
71 | - [Contribuyendo](#contribuyendo)
72 | - [Contacto](#contacto)
73 | - [Expresiones de gratitud](#expresiones-de-gratitud)
74 |
75 |
76 |
77 | ---
78 | ### Introducción
79 |
80 | #### Historia de JavaScript: ¿Qué es ECMAScript?
81 |
82 | **ECMAScript es el estándar que en la actualidad se encarga de regir como debe ser interpretado y funcionar el lenguaje JavaScript, a través de una serie de versiones que añaden funcionalidades nuevas.**
83 |
84 | *El primer navegador web:*
85 | - 1950: Inicio de las computadoras, surgen para analizar temas de la segunda guerra mundial.
86 |
87 | - 1969: Se creo la red ARPANET una forma de comunicar dos computadoras, para compartir información.
88 |
89 | - 1990: Tim Berners-lee Invento la World Wide Web las bases de la web.
90 |
91 | - 1993: Nacimiento de Mosaic primer navegador Web.
92 |
93 | - 1994: Marc Andreessen y James H. Clark fundaron Netscape Communications Corporation el primer navegador comercial y que inicio una revolución de la información.
94 |
95 | Entre 1995 y 2001, se enfrentaron Netscape y Microsoft para lograr posicionar comercialmente su propio navegador. Quizás Netscape fue el gran perdedor en las guerras de los navegadores es una de las historias más apasionantes de la crónica de la Red.
96 |
97 | - 1995: Internet Explorer primer navegador web creador por Microsoft. **Mocha** es un lenguaje de programación propuesta creada por Netscape, poco después sería nombrado **LiveScript** y finalmente JavaScript. **JScript** es un lenguaje de programación para la web propuesta creada por Microsoft.
98 |
99 | - 1996: CSS propuesta de estilos creado por Microsoft.
100 |
101 | - 1997: ECMA (*European Computer Manufacturer Association*) estandarizar múltiples lenguajes de programación surgido por parte de Netscape, Microsoft y otras empresas.
102 |
103 | *Evolución de ECMAScript*
104 |
105 |
106 |
107 |
108 |
109 | ---
110 | #### ¿Qué es el TC39?
111 |
112 | **TC39 grupo de desarrolladores, académicos encargados de revisar y actualizar cada nueva propuesta o funcionalidades, bajo el mando de ECMA. El estándar se caracteriza por una serie de pasos que cada propuesta sigue para publicar en alguna versión de ECMAScript**
113 |
114 | *Etapas de una nueva propuesta para ECMAScript*
115 |
116 | - Stage0: Strawperson (borrador, cualquier persona puede tener una idea para implementar en el estándar).
117 |
118 | - Stage1: Proposal (propuesta formal).
119 |
120 | - Stage2: Draft (borrador, como va a funcionar la implementación el impacto entre otros).
121 |
122 | - Stage3: Candidate (se elige el candidato, vamos a tener una propuesta que va ayudar a mejorar el lenguaje).
123 |
124 | - Stage4: Finished (va a ser desplegada en la versión normalmente en JUNIO).
125 |
126 |
127 |
128 | ---
129 | ### ECMAScript 6 (ES6 o ES2015)
130 |
131 | #### Let y const, y arrow function
132 |
133 | **Nueva forma para declarar variables let y const**
134 |
135 | Las palabras reservadas **let** y **const** solucionan algunos problemas de **var** tales como el *scope*, *hoisting*, *variables globales*, *re-declaración* y *re-asignación* de variables
136 |
137 | *Variables re-declaradas y re-asignadas*
138 |
139 | La re-declaración consiste en volver a declarar una variable, y la re-asignación es volver a asignar un valor a la variable. Cada palabra reservada (*var, let y const*) tiene una forma diferente de utilizar variables.
140 |
141 | - var: Puede ser re-declarada y re-asignada.
142 | - let: No se puede re-declarada pero si re-asignada.
143 | - const: No se puede re-declarada, ni re-asignada.
144 |
145 | Al momento de re-declarar una variable con let y const, este producirá un error "variable ya declarada"
146 |
147 | **Ejemplo de declaración y asignación en diferentes líneas**
148 |
149 | ```js
150 | // Declaración de variables
151 | var nombreVar
152 | let nombreLet
153 |
154 | // Asignación de variables
155 | nombreVar = "Soy Var"
156 | nombreLet = "Soy Let"
157 | ```
158 |
159 | **Ejemplo de declarar y asignar con const de diferentes líneas de código**
160 |
161 | ```js
162 | const valorPi
163 | valorPi = 3.14
164 | ```
165 |
166 | **Ejemplo de re-declaración de variables**
167 |
168 | ```js
169 | var nombreVar = "Soy var"
170 | let nombreLet = "Soy let"
171 | const nombreConst = "Soy const"
172 |
173 |
174 | // Re-declaración de variables
175 | var nombreVar = "var"
176 | console.log(nombreVar) // "var"
177 |
178 | let nombreLet = "let" // SyntaxError: Identifier 'nombreLet' has already been declared.
179 |
180 | const nombreConst = "const" //SyntaxError: Identifier 'nombreConst' has already been declared.
181 | ```
182 | **Ejemplo de re-asignación de variables**
183 |
184 | ```js
185 | var nombreVar = "Soy var"
186 | let nombreLet = "Soy let"
187 | const nombreConst = "Soy const"
188 |
189 | // Re-asignación de variables
190 | nombreVar = "otro var"
191 | console.log(nombreVar) // "otro var"
192 |
193 | nombreLet = "otro let"
194 | console.log(nombreLet) // "otro let"
195 |
196 | nombreConst = "Otro const" // TypeError: Assignment to constant variable.
197 | ```
198 |
199 |
200 |
201 | *Funciones flecha (arrow functions)*
202 |
203 | Consiste en una función anónima. Las funciones anónimas permite no asignarle a un nombre a un conjunto de instrucciones que deseamos ejecutarlo sin necesidad de asociarlo.
204 |
205 | ```js
206 | // Función tradicional
207 |
208 | function nombre (parámetros) {
209 | return valorRetornado
210 | }
211 |
212 | // Función flecha
213 |
214 | const nombre = (parámetros) => {
215 | return valorRetornado
216 | }
217 | ```
218 |
219 | *Omitir paréntesis en las funciones flecha*
220 |
221 | Si en la función existe un solo parámetro, puede omitir los paréntesis.
222 |
223 | ```js
224 | const multiplicaciónPorDos = num => {
225 | return num * 2
226 | }
227 | ```
228 |
229 | *Retorno implícito*
230 |
231 | Las funciones flecha tienen un retorno implícito, es decir, se puede omitir la palabra reservada **return**, esto con el fin de que el código sea escrito en una sola línea.
232 |
233 | ```js
234 | // Función tradicional
235 | function suma (num1, num2) {
236 | return num1 + num2
237 | }
238 |
239 | // Función flecha
240 | const suma = (num1, num2) => num1 + num2
241 | ```
242 |
243 | Si se requiere de más líneas y desea utilizarlo de una manera implícita, deberás envolver el cuerpo de la función entre paréntesis.
244 |
245 | ```js
246 | const suma = (num1, num2) => (
247 | num1 + num2
248 | )
249 | ```
250 |
251 |
252 |
253 | ---
254 |
255 | #### Strings
256 |
257 | *Concatenación de caracteres*
258 |
259 | Para crear una cadena larga, se puede utilizar la concatenación. Consiste en unir uno o varios caracteres,utilizando el signo de suma.
260 |
261 | ```js
262 | var nombre = "Ferney"
263 | var edad = 26
264 | var mensaje = "Mi nombre es " + nombre " y tengo " + edad + " años."
265 |
266 | console.log(mensaje) // "Mi nombre es Ferney y tengo 26 años."
267 | ```
268 |
269 | *Cómo utilizar las plantillas literales*
270 |
271 | Se emplea el carácter acento grave (`) y para incluir las variables se utiliza la sintaxis ```${variable}```
272 |
273 | ```js
274 | var nombre = "Ferney"
275 | var edad = 26
276 |
277 | var mensaje = `Mi nombre es ${nombre} y tengo ${edad} años.`
278 | console.log(mensaje) // "Mi nombre es Ferney y tengo 26 años."
279 | ```
280 |
281 | *Plantilla multilínea*
282 |
283 | Consiste en crear mensajes que contengan varias líneas separadas entre si, utilizando las plantillas literales. Antes la forma de crear una plantilla multilínea es agregando \n al string.
284 |
285 | ```js
286 | var mensaje = "Línea 1 \n" + "línea 2"
287 |
288 | console.log(mensaje)
289 | // 'Línea 1
290 | // línea 2'
291 | ```
292 |
293 | Con ES6 solo se necesita utilizar las plantillas literales
294 |
295 | ```js
296 | var mensaje = `Línea 1
297 | línea 2`
298 |
299 | console.log(mensaje)
300 | // 'Línea 1
301 | // línea 2'
302 | ```
303 |
304 |
305 | ---
306 |
307 | #### Parámetros por defecto
308 |
309 | Ayudan a definir un valor inicial a las variables que son recibidas en la función. Esto permite mejorar la legibilidad y el mantenimiento del código.
310 |
311 | ```js
312 | // Antes de ES6 se utilizaba los valores por defecto de la siguiente forma.
313 | function newUser(name, age, country){
314 | var name = name || "Ferney";
315 | var age = age || 24;
316 | var country = country || "Co";
317 | console.log(name, age, country);
318 | }
319 |
320 | newUser();
321 | newUser("Camila", 24, "MX");
322 |
323 | //Ahora con Es6 se utiliza de esta forma
324 |
325 | function newAdmin(name = "Ferney", age = 32, country = "CL"){
326 | console.log(name, age, country);
327 | }
328 |
329 | newAdmin();
330 | newAdmin("Ana", 28, "PE");
331 | ```
332 |
333 | *Posición de los parámetros por defecto*
334 |
335 | Si Obligatoriamente necesitas el valor como argumento, es necesario que los parámetros por defecto siempre deben estar en las posiciones finales.
336 |
337 | ```js
338 | function sumar (number1, number2 = 0){...}
339 | sumar(3)
340 | ```
341 |
342 |
343 |
344 | ---
345 | #### Asignación de desestructuración
346 |
347 | Es una expresión que consiste en extraer los valores de arrays o propiedades de objetos en distintas variables.
348 |
349 | *Desestructuración de objetos*
350 |
351 | Consiste en extraer las propiedades de un objeto en variables. Por medio del mismo nombre de la propiedad del objeto.
352 |
353 | ```js
354 | const objeto = {
355 | prop1: "valor1",
356 | prop2: "valor2",
357 | ...
358 | }
359 |
360 | // Desestructuración
361 | const { prop1, prop2} = objeto
362 | ```
363 |
364 | Antes de ES6, se necesitaba acceder al objeto con la notación punto o corchetes por cada propiedad que se necesita y asignar ese valor a una variable diferente.
365 |
366 | ```js
367 | var usuario = { nombre: "FerneyNava", edad: 26, plataforma: "Platzi" }
368 |
369 | var nombre = usuario.nombre
370 | var edad = usuario.edad
371 | var plataforma = usuario["plataforma"]
372 |
373 | console.log(nombre) // "FerneyNava"
374 | console.log(edad) // 26
375 | console.log(plataforma) // "Platzi"
376 | ```
377 |
378 | Gracias a desestructuración de objetos podemos realizar lo mismo, pero en una sola línea, logrando que el código sea más legible y mantenible
379 |
380 | ```js
381 | const usuario = { nombre: "FerneyNava", edad: 26, plataforma: "Platzi" }
382 | const { nombre, edad, plataforma } = usuario
383 |
384 | console.log(nombre) //"FerneyNava"
385 | console.log(edad) // 26
386 | console.log(plataforma) // "Platzi
387 | ```
388 |
389 | *Cambiar el nombre de las variables con desestructuración*
390 |
391 | Para cambiar los nombres de las propiedades del objeto, podemos utilizar la desestructuración de la siguiente forma:
392 |
393 | ```js
394 | const objeto = { prop1: "valor1", prop2: "valor2", ... }
395 |
396 | // Desestrcuturación
397 | const { prop1: newProp1, prop2: newProp2 } = objeto
398 | ```
399 |
400 | **Ejemplo**
401 |
402 | ```js
403 | const usuario = { nombre: "Ferney", edad: "26", plataforma: "Platzi"}
404 |
405 | const { nombre: name, edad: age, plataforma: platform } = usuario
406 |
407 | console.log(name) // "Ferney"
408 | console.log(age) // 26
409 | console.log(platform) // "Platzi"
410 |
411 | console.log(nombre) // Uncaught ReferenceError: nombre is not defined
412 | ```
413 |
414 | *Desestructuración en parámetros de una función*
415 |
416 | Al enviar un objeto como argumento en la invocación a la declaración de una función, puedes utilizar la desestructuración en los parámetros para obtener los valores diferentes. Hay que tener en cuenta que el nombre debe ser igual a la propiedad del objeto.
417 |
418 | ```js
419 | const usuario = { nombre: "Ferney", edad: "26", plataforma: "Platzi"}
420 |
421 | function datos( { nombre, edad, plataforma }){
422 | console.log(nombre, edad, plataforma)
423 | }
424 |
425 | datos(usuario) // "Ferney", 23, "Platzi"
426 | ```
427 |
428 | *Desestructuración de arrays*
429 |
430 | Consiste en extraer los valores de un array en variables, haciendo uso de las posiciones del array.
431 |
432 | ```js
433 | const array = [ 1, 2, 3, 4, 5]
434 |
435 | // Desestructuración
436 | const [ uno, dos, tres ] = array
437 |
438 | console.log(uno) // 1
439 | console.log(dos) // 2
440 | console.log(tres) // 3
441 | ```
442 |
443 | *Desestructuración para valores retornados de una función*
444 |
445 | En el momento en que una función retorna un array, puedes guardarlo en una variable. Por ende, se puede utilizar la desestructuración para utilizar esos valores por separado de manera legible.
446 |
447 | En el siguiente ejemplo, la función **useState** retorna un array con dos elementos: un valor y otra función actualizada.
448 |
449 | ```js
450 | function useState(value){
451 | return [value, updateValue()]
452 | }
453 |
454 | //Sin desestructuración
455 | const estado = useState(3)
456 | const valor = estado[0]
457 | const actualizador = estado[1]
458 |
459 | //Con desestructuración
460 | const [valor, actualizador] = useState(3)
461 | ```
462 |
463 |
464 | ---
465 |
466 | #### Spread operator
467 |
468 | Consiste en propagar los elementos de un iterable, ya sea un array o string utilizando tres puntos ( ... ) dentro de un array.
469 |
470 | ```js
471 | // Para Strings
472 | const array = [..."Ferney"] // [ "F", "e", "r", "n", "e", "y"]
473 |
474 | // En arrays
475 | const otherArray = [...array] // [ "F", "e", "r", "n", "e", "y"]
476 | ```
477 |
478 | *Copiar arrays utilizando el operador de propagación*
479 |
480 | Realizar una copia de un array, tendrás que tener cuidado de la referencia en memoria. Los arrays se guardan en una referencia en la memoria del computador, al crear una copia, este tendrá la misma referencia que el original. Por este motivo si cambias algo en la copia, también lo harás en el original.
481 |
482 | ```js
483 | const originalArray = [1,2,3,4,5]
484 | const copyArray = originalArray
485 | copyArray[0] = 0
486 |
487 | originalArray // [0,2,3,4,5]
488 | originalArray === copyArray // true
489 | ```
490 |
491 | Para lograr evitar esto, utiliza el operador de propagación para crear una copia del array que utilice una referencia en memoria diferente al original.
492 |
493 | ```js
494 | const originalArray = [1,2,3,4,5]
495 | const copyArray = [...originalArray]
496 | copyArray[0] = 0
497 |
498 | originalArray // [1,2,3,4,5]
499 | copyArray // [0,2,3,4,5]
500 | originalArray === copyArray //false
501 | ```
502 |
503 | *Arrays y añadir elementos con el operador de propagación*
504 |
505 | Para unir dos arrays con el operador de propagación, debes separarlos por comas en un array.
506 |
507 | ```js
508 | const array1 = [1,2,3]
509 | const number = 4
510 | const array2 = [5,6,7]
511 |
512 | const otherArray = [...array1, number, ...array2]
513 |
514 | otherArray // [1,2,3,4,5,6,7]
515 | ```
516 |
517 | *Cuidado con la copia en diferentes niveles de profundidad arrays*
518 |
519 | El operador de propagación sirve para producir una copia en un solo nivel de profundidad, si existen arrays dentro del array a copiar. Entonces los sub-elementos en cada nivel, tendrán la misma referencia de memoria en la copia y en el original.
520 |
521 | ```js
522 | const originalArray = [1, [2,3], 4,5]
523 | const copyArray = [...originalArray]
524 |
525 | originalArray[1] === copyArray[1] // true
526 | ```
527 |
528 | *Propiedades de propagación en un objeto*
529 |
530 | Consiste en expandir las propiedades de un objeto utilizando el [spread operator](#spread-operator). Funciona para crear nuevos objetos a partir de otros.
531 |
532 | ```js
533 | const objeto = {
534 | nombre: "Ferney",
535 | age: 26,
536 | }
537 |
538 | const usuario = {
539 | ...objeto,
540 | plataforma: "Platzi"
541 | }
542 | ```
543 |
544 | *Crear copias de objetos utilizando las propiedades de propagación*
545 |
546 | Semejante a crear copias de *arrays* utilizando el operador de propagación, se puede realizar copias de objetos en un solo nivel mediante las propiedades de propagación.
547 |
548 | Logrando que el segundo objeto tenga referencia en memoria diferente al original.
549 |
550 | ```js
551 | const objetoOriginal = {a: 1, b: 2}
552 | const objetoReferencia = objetoOriginal
553 | const objetoCopia = {...objetoOriginal}
554 |
555 | objetoReferencia === objetoOriginal // true
556 | objetoOriginal === objetoCopia // false
557 | ```
558 |
559 | *Cuidado con la copia en diferentes niveles de profundidad objetos*
560 |
561 | El operador de propagación sirve para crear una copia en un solo nivel de profundidad, si existen objetos dentro de un objeto a copiar. Entonces los sub-elementos en cada nivel, tendrán la misma referencia en el copia y en el original.
562 |
563 | ```js
564 | const original = {datos: [1, [2, 3], 4, 5]}
565 | const copia = {...original}
566 |
567 | original === copia // false
568 | original["datos"] === copia["datos"] // true
569 | ```
570 |
571 | Recientemente salió una forma de producir una copia profunda con **StructuredCole**, es una característica reciente. Como es una característica reciente tiene un soporte en navegadores de un 87.71%
572 |
573 | ```js
574 | // Array
575 | const originalArray = [1, [2,3], 4,5]
576 | const copyArray = structuredClone(originalArray)
577 |
578 | originalArray === copyArray // false
579 | originalArray[1] === copyArray[1] //false
580 |
581 | // Objeto
582 | const original = {datos: [1, [2, 3], 4, 5]}
583 | const copia = structuredClone(original)
584 |
585 | original === copia // false
586 | original["datos"] === copia["datos"] // false
587 | ```
588 |
589 | **Recurso articulo escrito por [midudev](https://midu.dev/como-clonar-un-array-en-javascript/) Cómo clonar un Array en JavaScript de forma correcta y sin problema**
590 |
591 | *Parámetro rest*
592 |
593 | Consiste en agrupar el residuo de elementos mediante la sintaxis de tres puntos ( ... ) seguido de una variable que contendrá los elementos en un array. Sirve para crear funciones que acepten cualquier número de argumentos para agruparlos en un array.
594 |
595 | ```js
596 | function hola (primero, segundo, ...resto){
597 | console.log(primero, segundo) // 1 2
598 | console.log(resto) // [3,4,5,6]
599 | }
600 |
601 | hola(1,2,3,4,5)
602 | ```
603 |
604 | También sirve para obtener los elementos restantes de un array u objeto usando desestructuración.
605 |
606 | ```js
607 | const objeto = {
608 | nombre: "Ferney",
609 | age: 26,
610 | plataforma: "Platzi"
611 | }
612 |
613 | const array = [0,1,2,3,4,5]
614 |
615 | const {plataforma, ...usuario} = objeto
616 | const [cero, ...positivos] = array
617 |
618 | usuario // { nombre: "Andres", age: 23 }
619 | positivos // [1, 2, 3, 4, 5]
620 | ```
621 |
622 | Es importe que el parámetro rest siempre debe estar en la ultima posición de los parámetros de la función, puesto de que existirá un error de sintaxis.
623 |
624 | ```js
625 | function hola (primero, ...rest, ultimo){ ... }
626 | // SyntaxError: Rest element must be last element.
627 | ```
628 |
629 | *Rest vs operador de propagación*
630 |
631 | El parámetro rest agrupa el residuo de elementos y siempre debe estar en la última posición, el operador de propagación expande los elementos de un iterable en un array y no importa en que lugar esté situado.
632 |
633 | ```js
634 | const array = [1,2,3,4,5]
635 |
636 | function hola (primero, segundo, ...resto) { // <- Parámetro Rest
637 | console.log(primero, segundo) // 1 2
638 | console.log(resto) // [3,4,5, "final"]
639 | }
640 |
641 | hola(...array, "final") //<- Operador de propagación
642 | //Lo mismo que hacer -> hola(1,2,3,4,5, "final")
643 | ```
644 |
645 |
646 |
696 |
697 | ---
698 |
699 | #### Promesas
700 |
701 | Las promesas es una forma de manejar el asincronismo en JavaScript y se representa como un objeto que puede generar un valor único a futuro, tiene dos estados, o esta resuelta o incluye una razón por la cual no ha sido resuelta la solución.
702 |
703 | *Cómo utilizar las promesas*
704 |
705 | La clase **Promise** y sus métodos **then** y **catch** fueron añadidos en ES6. Esto logra resolver un problema del manejo del asincronismo con *callbacks*, llamado *Callback Hell*
706 |
707 | La clases **Promise** es una función que recibe dos parámetros:
708 |
709 | - *resolve*: cuando la promesa es resulta.
710 | - *reject*: cuando la promesa es rechazada.
711 |
712 | No es necesario utilizar como nombres estos dos parámetros, puedes utilizar cualquier nombre.
713 |
714 | ```js
715 | const promesa = () => {
716 | return new Promise((resolver, reject) => {
717 | if(something) {
718 | //true o false
719 | resolver("Se ha resuelto la promesa")
720 | } else {
721 | reject("Se ha rechazado la promesa")
722 | }
723 | })
724 | }
725 |
726 | promesa()
727 | .then(respuesta => console.log(respuesta)) // En caso que se ejecute resolve
728 | .catch(error => console.log(error)) // En caso que se ejecute reject
729 | ```
730 |
731 |
732 |
733 | ---
734 |
735 | #### Clases
736 |
737 | Class es una forma para crear clases y manejar la herencia, logrando resolver problemas con el paradigma de programación orientado a objetos.
738 |
739 | *Estructura de las clases en JavaScript*
740 |
741 | La estructura de clases en JavaScript consiste en:
742 |
743 | - Definir la clase con la palabra reservada class, seguido del nombre.
744 |
745 | - La función constructora sirve para crear las variables necesarias en la instancia del objeto, a partir de los argumentos en la instancia.
746 |
747 | - Para definir atributos necesitas el contexto this, que representa la instancia del objeto.
748 |
749 | - Métodos para definir las acciones de las clases.
750 |
751 | - Para crear una instancia, deberás declarar una variable e invocar la clase con la palabra reservada new.
752 |
753 | ```js
754 | class user {
755 | // constructor
756 | constructor(name, age){
757 | this.name = name;
758 | this.age = age;
759 | }
760 |
761 | // metodos
762 | speak (){
763 | return "Hello";
764 | }
765 |
766 | greeting(){
767 | return `${this.speak()} ${this.name}`;
768 | }
769 |
770 | get uAge() { //get obtener. Obtener el valor de age
771 | return this.age;
772 | }
773 |
774 | set uAge(n) { //set asignar. Asignar al age el valor de n
775 | this.age = n;
776 | }
777 | }
778 |
779 | const platzi = new user("Ferney Nava", 26);
780 | console.log(platzi.uAge);
781 | console.log(platzi.uAge = 20);
782 | ```
783 |
784 | #### Module
785 |
786 | ES6 introduce una forma de manejar código en archivos de manera modular. Esto involucra **exportar** funciones o variables de un archivo, e **importarlas** en otros archivos donde se necesite.
787 |
788 | *Cómo utilizar los módulos de ECMAScript*
789 |
790 | Para utilizar los módulos, debes tener mínimo dos archivos, uno para exportar las funciones y otro que las importe para ejecutarlas.
791 |
792 | Es importante de que si iniciaste un proyecto con NPM (Node Package Manager) con Node.js, necesitas especificar que el código es modular en el archivo.json de la siguiente manera:
793 |
794 | ```json
795 | // package.json
796 | { ...
797 | "type": "module"
798 | }
799 | ```
800 |
801 | *Exportaciones de código*
802 |
803 | Consiste en crear funciones o variables para utilizarlas en otros archivos mediante la palabra reservada **export**.
804 |
805 | Por ejemplos, en el archivo *math_function.js* declaramos una función para sumar dos valores, el cual lo exportaremos.
806 |
807 | ```js
808 | //math_function.js
809 | export const add = (x,y) => {
810 | return x + y
811 | }
812 | ```
813 |
814 | ```js
815 | //math_function.js
816 | const add = (x,y) => {
817 | return x + y
818 | }
819 |
820 | export { add, otherFunction, ...}
821 | ```
822 |
823 | *Qué son las importaciones de código*
824 |
825 | Consiste en usar funciones o variables de otros archivos mediante la palabra reservada **import**, deberán estar siempre lo más arriba del archivo y utilizando el mismo nombre que el archivo original.
826 |
827 | Por ejemplos, importamos la función *add* del archivo *math_function.js* para utilizarla en un archivo *main.js*
828 |
829 | ```js
830 | // main.js
831 |
832 | import { add, otherFunction } from "./math_functions.js"
833 |
834 | add(2,2) // 4
835 | ```
836 |
837 | Si importamos el módulo con un nombre diferente, existirá un error de sintaxis.
838 |
839 | Para importar todas las funcionalidades de un archivo se utiliza un asterisco ( * ) y se puede cambiar el nombre para evitar la repetición de variables o funciones a través de la palabra reservada *as*.
840 |
841 | ```js
842 | // main.js
843 |
844 | import * as myMathModule from "./math_functions.js"
845 |
846 | myMathModule.add(2,2) // 4
847 | myMathModule.otherFunction()
848 | ```
849 |
850 | *Exportaciones por defecto*
851 |
852 | Si solo un valor será exportado, se puede utilizar **export default**. De esta manera no es necesario las llaves {} al exportar e importar.
853 |
854 | ```js
855 | //math_function.js
856 |
857 | export default function add (x,y){
858 | return x + y;
859 | }
860 | ```
861 |
862 | No se puede usar export default antes de declaraciones *const*, *let* o *var*, pero puedes exportarlas al final.
863 |
864 | ```js
865 | // ❌ Erróneo
866 | export default const add = (x,y) => {
867 | return x + y;
868 | }
869 |
870 | // ✅ Correcto
871 | const add = (x,y) => {
872 | return x + y;
873 | }
874 |
875 | export default add
876 | ```
877 |
878 | *Importaciones por defecto*
879 |
880 | Si únicamente un valor será importado, entonces se puede utilizar cualquier nombre en la importación. De esta manera no se necesario las llaves {}.
881 |
882 | ```js
883 | //Las siguientes importaciones son válidas
884 | import add from './math_functions.js'
885 | import suma from './math_functions.js'
886 | import cualquierNombre from './math_functions.js'
887 | ```
888 |
889 | *Combinar ambos tipos de exportaciones e importaciones*
890 |
891 | Teniendo las importaciones y exportaciones, nombradas y por defecto, entonces podemos combinarlas en un mismo archivo.
892 |
893 | ```js
894 | // module.js
895 |
896 | export const myExport = "Hola"
897 | function myFunction() { ... }
898 |
899 | export default myFunction
900 |
901 | // main.js
902 | import myFunction, { myExport } from "/module.js"
903 | ```
904 |
905 |
906 | ---
907 |
908 | #### Generator
909 |
910 | Son funciones especiales que pueden pausar su ejecución, luego volver al punto donde se quedaron, recordando su scope y seguir retornando valores.
911 |
912 | *Cómo utilizar generadores*
913 |
914 | La sintaxis de los generadores es la siguiente:
915 |
916 | - La palabra reservada function* (con el asterisco al final)
917 | - La palabra reservada *yield* que hace referencia al valor retornado cada vez que se invoque, recordando el valor anterior.
918 | - Crear una variable a partir de la función generadora.
919 | - El método *next* devuelve un objeto que contiene una propiedad *value* con cada valor de yield; y otra propiedad *done* con el valor *true* o *false* si el generador ha terminado.
920 |
921 | ```js
922 | function* nombre (parámetros){
923 | yield (primer valor retornado)
924 | yield (segundo valor retornado)
925 | ...
926 | yield (último valor retornado)
927 | }
928 |
929 | //crear el generador
930 | const generador = nombre(argumentos)
931 |
932 | // Invocaciones
933 | generador.next().value // primer valor retornado
934 | generador.next().value // segundo valor retornado
935 | ...
936 | generador.next().value // último valor retornado
937 | ```
938 |
939 | *Ejemplo de un generador*
940 |
941 | ```js
942 | function* generator (){
943 | yield 1
944 | yield 2
945 | yield 3
946 | }
947 |
948 | const generador = generator()
949 |
950 | generador.next().value // 1
951 | generador.next().value // 2
952 | generador.next().value // 3
953 | generador.next() // {value: undefined, done: true}
954 | ```
955 |
956 | *Cómo utilizar for of y for in*
957 |
958 | Existen dos nuevas formas de utilizar ciclos repetitivos. El bucle **for valor of iterable** recorre iterables, como arrays, Map, Set e incluso un generador.
959 |
960 | El valor es cada elemento del iterable, se inicia con *let nombre*. Puede tener cualquier nombre.
961 |
962 | ```js
963 | const array = [5, 6, 3, 2, 1]
964 |
965 | for (let numero of array){
966 | console.log(numero) // 5, 6, 3, 2, 1
967 | }
968 | ```
969 |
970 | Hay que tener en cuenta que solo podrás acceder a sus valores, y no a sus referencias, por lo que si quieres cambiar los elementos del array, necesitarás un índice array(índice).
971 |
972 | ```js
973 | for (let numero of array){
974 | numero *= 2
975 | console.log(numero) // 10 12 6 4 2
976 | }
977 |
978 | console.log(array) // [5, 6, 3, 2, 1]
979 | ```
980 |
981 | Si intentas recorrer un objeto de esta forma *for elemento of objeto*, ocurrirá un error, porque un objeto no es un iterable. En su lugar se utiliza *for elemento in objeto*, que recorrerá las propiedades del objeto.
982 |
983 | ```js
984 | const objeto = { a: 1, b: 2, c: 3 }
985 |
986 | for(let elemento in objeto) {
987 | console.log(elemento) // "a" "b" "c"
988 | }
989 | ```
990 |
991 | Si utiliza *for elemento in array*, no dará error, pero el resultado no será el esperado, puesto de que los arrays son un tipo de objeto donde cada propiedad es el índice del valor del array o del iterable.
992 |
993 | ```js
994 | const array = { 5, 4, 3, 2, 1 }
995 |
996 | for(let elemento in array) {
997 | console.log(elemento) // "0" "1" "2" "3" "4"
998 | }
999 | ```
1000 |
1001 |
1002 |
1003 | ---
1004 |
1005 | #### Set-add
1006 |
1007 | Es una nueva estructura de datos para almacenar elementos únicos, es decir, sin elementos repetidos.
1008 |
1009 | *Cómo utilizar los Sets*
1010 |
1011 | Para iniciar un *Set*, se debe crear una instancia de su clase a partir de un iterable. Un iterable es un objeto que permite recorrer una colección, como por ejemplo un *array*
1012 |
1013 | ```js
1014 | const set = new Set(iterable)
1015 | ```
1016 |
1017 | *Manipular los Sets*
1018 |
1019 | Para manipular los sets, existen los siguiente métodos:
1020 |
1021 | - add(value): Añade un nuevo valor.
1022 | - delete(value): Elimina un elemento que contiene el Set, retorna un booleano si existía o no el valor.
1023 | - has(value): Retorna un booleano si existe o no el valor dentro del Set.
1024 | - clear(value): Elimina todos los valores del Set.
1025 | - size: Retorna la cantidad de elementos del Set.
1026 |
1027 | **Recurso Map y Set [javaScript.info](https://es.javascript.info/map-set#filtrar-miembros-unicos-del-array)**
1028 |
1029 |
1030 |
1031 | ---
1032 |
1033 | ### ECMAScript 7 (ES7 o ES2016)
1034 |
1035 | #### Operador de potenciación y array includes
1036 |
1037 | Consiste en elevar una base a un exponente utilizando el doble asterisco ( ** )
1038 |
1039 | **base ** exponente**
1040 |
1041 | Ejemplo, calcula la potencia del siguiente número 5^3
1042 |
1043 | ```js
1044 | const potencia = 5**3
1045 |
1046 | console.log(potencia) // 125
1047 | ```
1048 |
1049 | *Método includes*
1050 |
1051 | Determina si un array o string incluye un determinado elemento. Devuelve **true** o **false**, si existe o no respectivamente.
1052 |
1053 | Este método recibe dos argumentos:
1054 | - El elemento a comparar
1055 | - El índice inicial desde donde comparar hasta el último elemento.
1056 |
1057 | *Índices positivos y negativos*
1058 |
1059 | Los índices positivos comienzan desde 0 hasta la longitud total menos uno, de izquierda a derecha del array.
1060 |
1061 | ```js
1062 | [0,1,2,3,....., lenght-1]
1063 | ```
1064 |
1065 | Los índices negativos comienzan desde -1 hasta el negativo de la longitud total del *array*, de derecha a izquierda.
1066 |
1067 | ```js
1068 | [-lenght, ..., -3, -2, -1]
1069 | ```
1070 |
1071 | *Ejemplos utilizando el método includes*
1072 |
1073 | Método includes se utiliza para arrays y strings. El método es sensible a mayúsculas, minúsculas y espacios.
1074 |
1075 | ```js
1076 | // Utilizando strings
1077 | const saludo = "Hola mundo"
1078 |
1079 | saludo.includes("Hola") // true
1080 | saludo.includes("Mundo") // false
1081 | saludo.includes(" ") // true
1082 | saludo.includes("Hola", 1) // false
1083 | saludo.includes("mundo", -5) // true
1084 | ```
1085 |
1086 | ```js
1087 | // Utilizando arrays
1088 | const frutas = ["manzana", "pera", "piña", "uva"]
1089 |
1090 | frutas.includes("manzana") // true
1091 | frutas.includes("Pera") // false
1092 | frutas.includes("sandía") // false
1093 | frutas.includes("manzana", 1) // false
1094 | frutas.includes("piña", -1) // false
1095 | frutas[0].includes("man") // true
1096 | ```
1097 |
1098 | En objetos también existen formas para saber si existe una propiedad. Solo evalúa las clases de los objetos. Con la siguiente palabra reservada y los siguientes métodos.
1099 |
1100 | - La palabra reservada in; evalúa todas las propiedades del objeto y del prototipo.
1101 | - El método de objetos **hasOwnProperty**; Evalúa solamente las propiedades del objeto.
1102 | - El método **Object.hasOwm**, que recibe el objeto y la propiedad a evaluar.
1103 |
1104 | ```js
1105 | // Utilizando arrays
1106 | const letras = {
1107 | a: 1,
1108 | b: 2,
1109 | c: 3
1110 | }
1111 |
1112 | console.log("a" in letras) //true en el objeto se encuentra la clave "a"
1113 | console.log(letras.hasOwmProperty("a")) // true en el objeto se encuentra la clave "a"
1114 | console.log(Object.hasOwm(letras, "a")) // true en el objeto se encuentra la clase "a"
1115 |
1116 | const letrass = {d: 4, e: 5, f: 7}
1117 |
1118 | console.log(letrass)
1119 | console.log(letrass.hasOwmProperty("toString")) // false
1120 | console.log("toString" in letras) // true por el objeto letrass tiene una prototipo que se llama toString
1121 | ```
1122 |
1123 |
1266 |
1267 | ---
1268 |
1269 | ### ECMAScript 9 (ES9 o ES2018)
1270 |
1271 | #### Expresiones regulares
1272 |
1273 | Las expresiones regulares o RegEx (regular expresions) son **patrones de búsqueda y manipulación de cadenas de caracteres**.
1274 |
1275 | En JavaScript se crea este patrón entre barras inclinadas (/patrón/) y se utiliza métodos para hacer coincidir la búsqueda.
1276 |
1277 | ```js
1278 | const regexData = /([0-9]{4})-([0-9]{2})-([0-9]{2})/
1279 | const match = regesData.exec("2018-04-20")
1280 | ```
1281 |
1282 |
1333 |
1334 | ---
1335 |
1336 | ### ECMAScript 10 (ES10 o ES2019)
1337 |
1338 | #### Flat-map y trimStart-trimEnd
1339 |
1340 | *Qué es el aplanamiento de arrays*
1341 |
1342 | Consiste en transformar un array de arrays a una sola dimensión. Los métodos *flat* y *flatMap* permitirán realizar el aplanamiento.
1343 |
1344 | *Método flat*
1345 |
1346 | Devuelve un *array* donde los sub-arrays han sido propagados hasta una profundidad especifica.
1347 |
1348 | Este método es inmutable, es decir, retorna un nuevo array con los cambios y no cambia el array original.
1349 |
1350 | Este método recibe un argumento:
1351 |
1352 | - La *profundidad* del aplanamiento, por defecto, tiene un valor de 1.
1353 |
1354 | Se puede aplanar todos los sub-arrays en una sola dimensión, utilizando el valor de *Infinity*
1355 |
1356 | ```js
1357 | const array = [1,2[3,4],5,6]
1358 | const result = array.flat()
1359 | result // [1,2,3,4,5,6]
1360 |
1361 | const array2 = [1, 2, [3, 4, [5, 6]]]
1362 | const result2 = array2.flat()
1363 | result2 // [1, 2, 3, 4, [5, 6]]
1364 |
1365 | const array3 = [1, 2, [3, 4, [5, 6]]]
1366 | const result3 = array3.flat(2)
1367 | result3 // [1, 2, 3, 4, 5, 6]
1368 |
1369 | const array4 = [1, 2, [3, 4, [5, 6, [7, 8, [9, 10]]]]]
1370 | const result4 = array4.flat(Infinity)
1371 | result4 // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
1372 | ```
1373 |
1374 | *Método flatMap*
1375 |
1376 | Es un combinación de los métodos *map* y *flat*. Primero realiza la interacción de los elementos del array (como si fuera map), y después los aplana en una sola profundidad (como si fuera *flat*)
1377 |
1378 | Este método es **inmutable**, es decir, retorna un nuevo array con los cambios y no cambia el array original.
1379 |
1380 | El método recibe los mismos argumentos que el método map.
1381 |
1382 | ```js
1383 | const strings = ["Nunca pares", "de Aprender"]
1384 | strings.map(string => string.split(""))
1385 | // [['Nunca', 'pares'], ['de', 'Aprender']]
1386 | strings.flatMap(string => string.split(""))
1387 | // ['Nunca', 'pares', 'de', 'Aprender']
1388 |
1389 | const numbers = [1,2,3,4]
1390 | numbers.map(number => [number * 2])
1391 | // [[2],[4],[6],[8]]
1392 | numbers.flatMap(number => [number *2])
1393 | // [2,4,6,8]
1394 |
1395 | // Cuidado, primero hace el map y luego el flat
1396 | const numbers2 = [1,[2,3], 4, 5]
1397 | numbers2.flatMap(number => [number * 2])
1398 | // [2, NaN, 8, 10]
1399 | // Recuerda: NaN = No a Number
1400 | ```
1401 |
1402 | *Eliminar espacios en blanco de un string*
1403 |
1404 | Existen tres métodos para *eliminar espacio en blanco* de un string
1405 |
1406 | - El método *trim* elimina los espacios en blanco al inicio y al final.
1407 | - EL método *trimStart* o *trimLeft* elimina los espacios al inicio.
1408 | - El método *trimEnd* o *trimRight* elimina los espacios al final.
1409 |
1410 | ```js
1411 | const saludo = " hola "
1412 | const result1 = saludo.trim()
1413 | const result2 = saludo.trimStart()
1414 | const result3 = saludo.trimEnd()
1415 |
1416 | result1 // "hola"
1417 | result2 // "hola "
1418 | result3 // " hola"
1419 | ```
1420 |
1421 |
1422 |
1423 | ---
1424 |
1425 | #### Try catch y fromEntries
1426 |
1427 | *Parámetro opcional de catch*
1428 |
1429 | El parámetro de *catch*, permite omitir el error si es necesario.
1430 |
1431 | ```js
1432 | try {
1433 | // Manejar el código
1434 | } catch (err) {
1435 | // Se utiliza el parámetro 'err'
1436 | }
1437 |
1438 | try {
1439 | // Manejar el código
1440 | } catch {
1441 | // Manejar el error sin el parámetro.
1442 | }
1443 | ```
1444 |
1445 | Se recomienda manejar el error como parámetro, puesto de que tiene más información del problema.
1446 |
1447 | *Cómo transformar un array de arrays en un objeto*
1448 |
1449 | El método **Object.fromEntries** devuelve un objeto a partir de un arrays donde sus elementos son las *entries* en forma [propiedad, valor]
1450 |
1451 | Se puede considerar la opción inversa de **Object.entries()**. *entries()* transforma el objectos a arrays y en cambio el *fromEntries()* transforma el array en objeto.
1452 |
1453 | ```js
1454 | const arrayEntries = [
1455 | ['name', 'Ferney'],
1456 | ['email', 'ferneynava@gmail.com'],
1457 | ['age', 26]
1458 | ]
1459 |
1460 | const usuario = Object.fromEntries(arrayEntries)
1461 |
1462 | console.log(usuario)
1463 | /* {
1464 | name: 'Ferney',
1465 | email: 'ferneynava@gmail.com'
1466 | age: 26
1467 | }
1468 | ```
1469 |
1470 |
1471 |
1472 | ---
1473 |
1474 | ### ECMAScript 11 (ES11 o ES2020)
1475 |
1476 | #### Optional chaining
1477 |
1478 | Cuando intentas acceder a propiedades de un objeto que no existen, JavaScript retornará *undefined*.
1479 |
1480 | ```js
1481 | const usuario = {}
1482 | console.log(usuario.redes) // undefined
1483 | ```
1484 |
1485 | Al acceder a una propiedad más profunda de un objeto, que previamente fue evaluada como *undefined*, el programa se detendrá y mostrará un error.
1486 |
1487 | ```js
1488 | const usuario = {}
1489 | console.log(usuario.redes.facebook)
1490 | // TypeError: Cannot read properties of undefined (reading 'facebook')
1491 | ```
1492 |
1493 | Ejecutar *undefined.facebook* es un error de tipo, debido a que *undefined* es un primitivo, no es un objeto.
1494 |
1495 | *Cómo utilizar el encadenamiento opcional*
1496 |
1497 | Optional chaining (?.) detiene la evaluación del objeto cuando el valor es *undefined* o *null* antes del (?.), retornara *undefined* sin detener el programa por un error.
1498 |
1499 | ```js
1500 | const usuario = {}
1501 | console.log(usuario.redes?.facebook)
1502 | //undefined
1503 | ```
1504 |
1505 | Pero, ¿por qué usaría propiedades de un objeto vacío? Cuando realizas peticiones, el objeto no contiene la información solicitada en seguida, por ende, necesitas que el programa no colapse hasta que lleguen los datos y puedas utilizarlos.
1506 |
1507 | *No abuses del encadenamiento opcional*
1508 |
1509 | El encadenamiento opcional se debe utilizar únicamente cuando probablemente un valor no exista.
1510 |
1511 | Por ejemplo, en un objeto *usuario* que siempre existe, pero la propiedad redes es opcional, entonces se debería escribir *usuario.redes?.facebook* y no *usuario?.redes?.facebook*.
1512 |
1513 | Si abusas del encademiento opcional y existe un error en un objeto, el programa podría "ocultarlo" por un *undefined*, provocando que el *debugging* sea más complicado.
1514 |
1515 |
1516 |
1517 | ---
1518 |
1519 | #### BigInt y Nullish
1520 |
1521 | *BigInt, números enteros muy grandes*
1522 |
1523 | El dato primitivo *bigint* permite **manejar números enteros muy grandes**. Existen dos formas de crear un *bigint*: el número entero seguido de *n* o mediante la función *BigInt*.
1524 |
1525 | ```js
1526 | const aBigNumber = 899867566537653456456n
1527 | const anotherBigNumber = BigInt(899867566537653456456)
1528 |
1529 | typeof 899867566537653456456n // "bigint"
1530 | ```
1531 |
1532 | JavaScript tiene límites numéricos, un máximo **Number.MAX_SAFE_INTEGER** y un mínimo **Number.MIN_SAFE_INTEGER**
1533 |
1534 | ```js
1535 | const max = Number.MAX_SAFE_INTEGER // 9007199254740991
1536 | const min = Number.MIN_SAFE_INTEGER // -9007199254740991
1537 | ```
1538 |
1539 | Al pasar de los limites anteriormente mencionados, los cálculos muestran resultados erróneos. Los *bigint* ayudan a manejar operaciones de enteros fuera de los límites.
1540 |
1541 | ```js
1542 | const increment = 2
1543 | const number = Number.MAX_SAFE_INTEGER + increment // 9007199254740992 sin el BigInt
1544 | const bigInt = BigInt(Number.MAX_SAFE_INTEGER) + BigInt(increment) //9007199254740993n con el BigInt
1545 | ```
1546 |
1547 | Se añade la misma cantidad a ambos tipos de datos, sin embargo, el tipo numérico da un resultado diferente al esperado.
1548 |
1549 | *Operador Nullish Coalescing*
1550 |
1551 | El operador nullish coalescing ( ?? ) consiste en evaluar una variable si es *undefined* o *null* para asignarle un valor.
1552 |
1553 | El siguiente ejemplo se lee como: ¿usuario.name es undefined o null? Si es así, asígnale un valor por defecto "Ferney", caso contrario asigna el valor de usuario.name.
1554 |
1555 | ```js
1556 | const usuario1 = {}
1557 | const nombre1 = usuario1.name ?? "Ferney"
1558 |
1559 | const usuario2 = {name: "Camilo"}
1560 | const nombre2 = usuario2.name ?? "Ferney"
1561 |
1562 | console.log(nombre1) // 'Ferney'
1563 | console.log(nombre2) // 'Camilo'
1564 | ```
1565 |
1566 | *Diferencia entre el operador OR y el Nullish coalescing*
1567 |
1568 | El operador OR ( || ) evalúa un valor false. Un valor false es aquel que es falso en un contexto booleano, estos son: 0, "" (string vacío), false, NaN, undefined o null.
1569 |
1570 | Puede que reciba una variable con un valor false que necesitas asignarle a otra variable, que no sea null o undefined. Si evalúas con el operador OR, este lo cambiará, provocando un resultado erróneo.
1571 |
1572 | ```js
1573 | const id = 0
1574 |
1575 | const orId = id || "Sin id"
1576 | const nullish = id ?? "Sin id"
1577 |
1578 | console.log(orId) // Sin id
1579 | console.log(nullish) // 0
1580 | ```
1581 |
1582 |
1628 |
1629 | ---
1630 |
1631 | #### GlobalThis y matchAll
1632 |
1633 | *Objeto global para cualquier plataforma*
1634 |
1635 | El motor de JavaScript, compila tu archivo y lo convierte en código que entiende el computador, al iniciar la compilación crea un objeto global.
1636 |
1637 | Este objeto global proporciona funciones y variables propias e integradas en el lenguaje o el entorno. Dependiendo la plataforma, este objeto global tendrá un nombre diferente.
1638 |
1639 | En el navegador el objeto global es *window*, para Node.js es *global*, y así para cada entorno. Sin embargo, en Node.js no podrás acceder a *window*, ni en el navegador podrás acceder a *global*.
1640 |
1641 | Para estandarizar el objeto global se creó *globalThis*, un objeto compatible para cualquier plataforma.
1642 |
1643 | ```js
1644 | // Ejecuta el siguiente código y observa que muestra
1645 | console.log(window)
1646 | console.log(globalThis)
1647 |
1648 | // En el navegador
1649 | window === globalThis // true
1650 |
1651 | // En Node.js
1652 |
1653 | global === globalThis // true
1654 | ```
1655 |
1656 | *Método matchAll para expresiones regulares*
1657 |
1658 | El método matchAll de los strings **devuelve un iterable** con todas las coincidencias del strings específico a partir de una expresión regular, colocada como argumento.
1659 |
1660 | ```js
1661 | const regex = /\b(Apple)+\b/g
1662 | const fruit = "Apple, Banana, Kiwi, Apple, Orange, etc. etc. etc."
1663 |
1664 | // Transformación del iterable retornado a array
1665 | const array = [...fruit.matchAll(regex)]
1666 | console.log(array)
1667 |
1668 | /*
1669 | [
1670 | [
1671 | 'Apple',
1672 | 'Apple',
1673 | index: 0,
1674 | input: 'Apple, Banana, Kiwi, Apple, Orange, etc. etc. etc.',
1675 | groups: undefined
1676 | ],
1677 | [
1678 | 'Apple',
1679 | 'Apple',
1680 | index: 21,
1681 | input: 'Apple, Banana, Kiwi, Apple, Orange, etc. etc. etc.',
1682 | groups: undefined
1683 | ]
1684 | ]
1685 | */
1686 | ```
1687 |
1688 |
1735 |
1736 | ---
1737 |
1738 | ### ECMAScript 12 (ES12 o ES2021)
1739 |
1740 | #### Numeric-separators y replaceAll
1741 |
1742 | *Separadores numéricos*
1743 |
1744 | Ayudan a la legibilidad de cantidades con varias cifras. Se utiliza el carácter guion bajo ( _ ) para separar las cifras, y no afecta a la ejecución del programa.
1745 |
1746 | Lo ideal es separar cada 3 cifras, para visualizar los miles, millones, billones, etc.
1747 |
1748 | ```js
1749 | // Baja legibilidad
1750 | const numero1 = 3501548945
1751 | console.log(numero1) // 3501548945
1752 |
1753 | // Alta legibilidad
1754 | const numero2 = 3_501_548_945
1755 | console.log(numero2) // 3501548945
1756 | ```
1757 |
1758 | De esta manera podemos identificar el número rápidamente.
1759 |
1760 | *Método replaceAll*
1761 |
1762 | El método *replaceAll* retorna un nuevo string, remplazando todos los elementos por otro.
1763 |
1764 | Este método recibe dos argumentos:
1765 | - El patrón a reemplazar, puede ser un string o una expresión regular.
1766 | - El nuevo elemento que sustituye al reemplazado.
1767 |
1768 | Este método soluciona el problema que tenía *replace*, que realizaba la misma función de reemplazar elementos, pero solamente *una sola vez* por invocación.
1769 |
1770 | ```js
1771 | const mensaje = "JavaScript es maravilloso, con JavaScript puede crear el futuro de la web."
1772 |
1773 | mensaje.replace("JavaScript", "Python")
1774 | // "Python es maravillo, con JavaScript puede crear el futuro de la web."
1775 |
1776 | mensaje.replaceAll("JavaScript", "Python")
1777 | // "Puthon es maravillo, con Python puede crear el futuro de la web."
1778 |
1779 | mensaje.replaceAll(/a/g, "*")
1780 | // "J*v*Script es m*r*villoso, con J*v*Script puede cre*r el futuro de l* web."
1781 | ```
1782 |
1783 |
1824 |
1825 | ---
1826 |
1827 | ### ECMAScript 13 (ES13 o ES2022)
1828 |
1829 | #### At
1830 |
1831 | El método *at* de arrays sirve para **acceder a los elementos a partir del índice.**
1832 |
1833 | *Índices positivos y negativos*
1834 |
1835 | Los índices positivos comienzan desde 0 hasta la longitud total menos uno, de izquierda a derecha del array.
1836 |
1837 | ```js
1838 | [0,1,2,3,....., lenght-1]
1839 | ```
1840 |
1841 | Los índices negativos comienzan desde -1 hasta el negativo de la longitud total del *array*, de derecha a izquierda.
1842 |
1843 | ```js
1844 | [-lenght, ..., -3, -2, -1]
1845 | ```
1846 |
1847 | *Cómo utilizar el método at*
1848 |
1849 | La utilidad más importante de este método es para manejar *índices negativos*. Algo que no se puede con la notación de corchetes.
1850 |
1851 | ```js
1852 | const nombres = ["Andres", "Monica", "Damaris", "Lina", "Ramiro"]
1853 |
1854 | nombres.at(-1) // "Ramiro"
1855 | nombres[-1] // undefined
1856 | nombres.at(-3) // Damaris
1857 | nombres[nombres.length - 1] // "Lina"
1858 | ```
1859 |
1860 | Se puede utilizar la notación de corchetes, pero necesitas obtener la longitud del *array* y restarle una unidad, generando mucho código que puede volverse difícil de leer.
1861 |
1862 | ```js
1863 | const nombres = ["Andres", "Monica", "Damaris", "Lina", "Ramiro"]
1864 |
1865 | nombres[nombres.length - 1] // "Lina"
1866 | ```
1867 |
1868 |
1869 |
1870 | ---
1871 |
1872 | #### Top level await en el consumo de una API
1873 |
1874 | Permite utilizar la palabra reservada *await*, sin estar dentro de una función asíncrona con *async*. Sin embargo, únicamente se puede utilizar *await* en la parte superior del archivo de un módulo.
1875 |
1876 | *Cómo utilizar top level await*
1877 |
1878 | Cuando se introdujo funciones asíncronas, si utilizabas *await* fuera de *async*, existirá un error de sintaxis.
1879 |
1880 | ```js
1881 | // Error
1882 | await fetch(URL)
1883 | // SyntaxError: await is only valid in async function
1884 | ```
1885 |
1886 | Ahora, con *top level await* esto es posible, sin ningún error. Esto puede servir para importaciones de manera dinámica o iniciar la conexión de tus bases de datos. Siempre y cuando respetes que debe estar en la parte encima del archivo de tipo módulo.
1887 |
1888 |
1889 |
1890 | ---
1891 |
1892 | ### Contribuyendo
1893 |
1894 | Las contribuciones son lo que hace que la comunidad de código abierto sea un lugar increíble para aprender, inspirar y crear. Cualquier contribución que hagas es muy apreciada.
1895 |
1896 | Si tiene una sugerencia que mejoraría esto, bifurque el repositorio y crea una solicitud de extracción. También puede simplemente abrir un problema con la etiqueta "mejora". ¡No olvides darle una estrella al proyecto! ¡Gracias de nuevo!
1897 |
1898 | 1. Bifurcar el repositorio
1899 | 2. Crea tu rama de funciones (`git checkout -b `)
1900 | 3. Confirme sus cambios (`git commit -m "mensaje del commit'`)
1901 | 4. Empuje a la rama (`git push origin branch`)
1902 | 5. Abrir una solicitud de extracción
1903 |
1904 |