{"id":13299633,"url":"https://github.com/lonperman/Curso-EcmaScript","last_synced_at":"2025-03-10T11:32:19.000Z","repository":{"id":64912417,"uuid":"579151037","full_name":"lonperman/Curso-EcmaScript","owner":"lonperman","description":null,"archived":false,"fork":false,"pushed_at":"2022-12-23T22:54:25.000Z","size":95,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2023-03-03T18:57:25.964Z","etag":null,"topics":["ecmascript","ecmascript6","javascript"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lonperman.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-12-16T19:44:49.000Z","updated_at":"2022-12-18T21:57:54.000Z","dependencies_parsed_at":"2022-12-17T17:37:01.216Z","dependency_job_id":null,"html_url":"https://github.com/lonperman/Curso-EcmaScript","commit_stats":null,"previous_names":[],"tags_count":null,"template":null,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lonperman%2FCurso-EcmaScript","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lonperman%2FCurso-EcmaScript/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lonperman%2FCurso-EcmaScript/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lonperman%2FCurso-EcmaScript/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lonperman","download_url":"https://codeload.github.com/lonperman/Curso-EcmaScript/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":221170224,"owners_count":16768655,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ecmascript","ecmascript6","javascript"],"created_at":"2024-07-29T17:37:45.619Z","updated_at":"2024-10-23T07:30:58.012Z","avatar_url":"https://github.com/lonperman.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# **Table of Content**\n\n## ⚙ EcmaScript 6\n- ### [Scope (Alcance de una variable)](https://github.com/lonperman/Curso-EcmaScript#-scope-alcance-de-una-variable)\n- ### [Arrow Functions](https://github.com/lonperman/Curso-EcmaScript#-arrow-functions-funciones-flecha)\n- ### [Template Literals (Uso de strings y variables)](https://github.com/lonperman/Curso-EcmaScript#-template-literals-uso-de-strings-y-variables)\n- ### [Default-params. (Definicion de parametros con valor por defecto)](https://github.com/lonperman/Curso-EcmaScript#-default-params-definicion-de-parametros-con-valor-por-defecto)\n- ### [Destructuring, Spread operator, Rest-params.](https://github.com/lonperman/Curso-EcmaScript#-destructuring-spread-operator-rest-paramsdestructurar-arreglos-y-objetospropagar-la-informacion)\n- ### [ Object-literals (Mejora a los objetos)](https://github.com/lonperman/Curso-EcmaScript#-object-literals-mejora-a-los-objetos-1)\n- ### [Promises (Algo que va a suceder o no).](https://github.com/lonperman/Curso-EcmaScript#-promises-algo-que-va-a-suceder-o-no)\n- ### [Clases (Diseño de clases - Utilizando herencia)](https://github.com/lonperman/Curso-EcmaScript#-clases-dise%C3%B1o-de-clases---utilizando-herencia)\n- ### [Module (exportar \u0026 importar funciones de diferentes archivos)](https://github.com/lonperman/Curso-EcmaScript#-module-exportar--importar-funciones-de-diferentes-archivos)\n- ### [Generadores](https://github.com/lonperman/Curso-EcmaScript#-generadores)\n- ### [Set (estructura de datos para almacenar elementos únicos)](https://github.com/lonperman/Curso-EcmaScript#-set) \n## ⚙ EcmaScript 7\n- ### [Exponential](https://github.com/lonperman/Curso-EcmaScript#1%EF%B8%8F%E2%83%A32%EF%B8%8F%E2%83%A3-exponential) \n- ### [Includes](https://github.com/lonperman/Curso-EcmaScript#1%EF%B8%8F%E2%83%A33%EF%B8%8F%E2%83%A3-includes)\n## ⚙ EcmaScript 8\n- ### [Object-entries](https://github.com/lonperman/Curso-EcmaScript#-object-entries)\n- ### [Object-values](https://github.com/lonperman/Curso-EcmaScript#-object-values)\n- ### [Object-keys](https://github.com/lonperman/Curso-EcmaScript#-object-keys)\n- ### [String padding](https://github.com/lonperman/Curso-EcmaScript#-string-padding)\n- ### [Trailing commas](https://github.com/lonperman/Curso-EcmaScript#-trailing-commas)\n- ### [Funciones asíncronas](https://github.com/lonperman/Curso-EcmaScript#-funciones-as%C3%ADncronas)\n## ⚙ EcmaScript 9\n- ### [Expresiones regulares](https://github.com/lonperman/Curso-EcmaScript#-expresiones-regulares)\n- ### [Método finally en promesas](https://github.com/lonperman/Curso-EcmaScript#-m%C3%A9todo-finally-en-promesas)\n- ### [Generadores asíncronos](https://github.com/lonperman/Curso-EcmaScript#-generadores-as%C3%ADncronos)\n## ⚙ EcmaScript 10\n- ### [flat-map y trimStart-trimEnd](https://github.com/lonperman/Curso-EcmaScript#-flat-map-y-trimstart-trimend)\n- ### [try catch y fromEntries](https://github.com/lonperman/Curso-EcmaScript#-try-catch-y-fromentries)\n## ⚙ EcmaScript 11\n- ### [Optional chaining](https://github.com/lonperman/Curso-EcmaScript#-optional-chaining)\n- ### [BigInt y Nullish](https://github.com/lonperman/Curso-EcmaScript#-bigint-y-nullish)\n- ### [Promise.allSettled](https://github.com/lonperman/Curso-EcmaScript#-promiseallsettled)\n- ### [globalThis y matchAll](https://github.com/lonperman/Curso-EcmaScript#-globalthis-y-matchall)\n- ### [Método matchAll para expresiones regulares.](https://github.com/lonperman/Curso-EcmaScript#-m%C3%A9todo-matchall-para-expresiones-regulares)\n- ### [Dynamic Import](https://github.com/lonperman/Curso-EcmaScript#-dynamic-import)\n## ⚙ EcmaScript 12\n- ### [numeric-separators y replaceAll](https://github.com/lonperman/Curso-EcmaScript#-numeric-separators-y-replaceall)\n- ### [promise-any y métodos privados](https://github.com/lonperman/Curso-EcmaScript#-promise-any-y-m%C3%A9todos-privados)\n## ⚙ EcmaScript 13\n- ### [at](https://github.com/lonperman/Curso-EcmaScript#-at)\n- ### [top level await en el consumo de una API](https://github.com/lonperman/Curso-EcmaScript#-top-level-await-en-el-consumo-de-una-api)\n\n--------------------\n# ⚙ EcmaScript 6\n## 🛠 Scope (Alcance de una variable)\n   \u003e Las formas de definir una variable en JavaScript como lo son var, let y const, tienen presente un respectivo alcance por lo cual se debe tener presente al momento de ser definidas en el desarrollo de un proyecto.\n\n\n```\n👨‍🔧 const fruits = () =\u003e {\n        if(true){\n            var fruit1 = 'Apple'; // function scope\n            let fruit2 = 'Kiwi'; // block scope\n            const fruit3 = 'Banana'; // block scope\n        }\n\n    📢 console.log(fruit1); // La variable var se imprime\n    📢 console.log(fruit2); // variable let no se imprime por su respectivo scope\n    📢 console.log(fruit3) //variable const no se imprime por su respectivo scope\n    }\n\n👨‍💻 fruits()\n\n✅ ---\u003e Result: 1️⃣ Console.log(fruit1) =\u003e Apple\n❌ ---\u003e Result: 2️⃣ Console.log(fruit2) =\u003e fruit2 is not defined.\n❌ ---\u003e Result: 3️⃣ Console.log(fruit3) =\u003e fruit3 is not defined.\n\n```\n\n## 🛠 Arrow Functions (Funciones Flecha)\n\u003e En la version de ecmaScript 6 contamos con las funciones flecha en donde se agrega una nueva forma de definir una funcion ademas de la forma convencional de como se definen dentro del desarrollo de un proyecto.\n\n```\n// Forma normal de definir una funcion.\n\n👨‍🔧  function square(num){\n        return num*num;\n    }\n\n👨‍💻 ---\u003e console.log(square(3));\n✅ ---\u003e Result: 9\n```\n\n```\n// Forma de definir una funcion como arrow-function.\n\n👨‍🔧  const square = (num) =\u003e {\n        return num*num;\n    }\n\n👨‍💻 ---\u003e console.log(square(3));\n✅ ---\u003e Result: 9\n\n// Arrow con el return implicito\n\n🔨 const square = num =\u003e num*num;\n\n👨‍💻 ---\u003e console.log(square(3));\n✅ ---\u003e Result: 9\n```\n## 🛠 Template Literals (Uso de strings y variables)\n  \u003e Los templates literals se utilizan para plasmar textos de una manera más dinamica, ya que este nos permite utilizar string y variables dentro de un mismo texto o parrafo dandonos la opcion de cambiar ciertos elementos y ahorrandonos en si, el volver escribir el mismo texto y tener que cambiar ciertas palabras.\n\n```\n👨‍🔧 let hello = 'Hello';\n👨‍🔧 let world = 'World';\n👨‍🔧 let epicPhrase = hello + ' ' + world + '!';\n\n// Forma normal.\n👨‍💻 console.log(epicPhrase);\n✅ ---\u003e Result: Hello World!\n\n// Template Literals\n👨‍🔧 let epicPhrase2 = `${hello} ${world}`;\n\n👨‍💻 console.log(epicPhrase2)\n✅ ---\u003e Result: Hello World\n```\n\n\u003e Los temple literals nos pueden ahorrar el tener que estar indicandole donde realizar un salto de linea.\n\n```\n// Multi-line strings\n👨‍🔧 let lorem = 'esto es un string \\n' + 'esto es otra linea';\n\n// Temple-literal\n👨‍🔧 let lorem2 = `Esta es una frase epica\n la continuacion de esa frase epica.`;\n\n👨‍💻 console.log(lorem);\n👨‍💻 console.log(lorem2)\n\n✅ ---\u003e esto es un string \n        esto es otra linea // 1️⃣ Primer console\n\n✅ ---\u003e Esta es una frase epica\n        la continuacion de esa frase epica. // 2️⃣ Segundo console.\n```\n\n## 🛠 Default-params. (Definicion de parametros con valor por defecto)\n\u003e Aveces cuando estamos desarrollando un  programa definimos cierta cantidad de parametros los cuales debemos enviarle a una funcion al momento de querer operarla, pero en ocaciones otro desarrollador puede pasar por desapercibido alguno de los argumentos, y esto podria causar que al momento de ejecurtar la funcion, esta arroje un error, pero si utilizamos ciertos valores por defecto en la definicion en nuestras variables podemos ahorranos complicaciones.\n\n```\n// Forma normal de definir variables por defecto.\n\n👨‍🔧 function newUser(name, age, country){\n    var name = name || 'Manuel';\n    var age = age || 25;\n    var country = country || 'CO';\n    console.log(name, age, country);\n}\n\n👨‍💻 newUser(); \n✅ ---\u003e Result: Manuel 25 CO\n\n👨‍💻 newUser('Alejo',25,'CO');\n✅ ---\u003e Result: Alejo 25 CO\n```\n\n```\n//Forma de definir por defecto los parametros desde su construccion.\n\n👨‍🔧  function newAdmin(name = 'Manuel', age = 25, country = 'CL'){\n        console.log(name, age, country);\n    }\n\n👨‍💻 newAdmin();\n✅ ---\u003e Result: Alejo 25 CO\n```\n## 🛠 Destructuring, Spread operator, Rest-params.(Destructurar arreglos y objetos,Propagar la informacion)\n\n```\n// Arrays destructuring\n\nlet fruits = ['Apple', 'Banana'];\nlet [a,b] = fruits;\n👨‍💻 console.log(a, fruits[1]);\n✅ ---\u003e Result: Apple Banana\n\n// Object destructuring\n\nlet user = { username: 'Manuel', age: 24};\nlet { username, age } = user;\n👨‍💻 console.log(username, user.age)\n✅ ---\u003e Result: Manuel 24\n```\n\u003e Metodo que nos permite propagar las propiedades sin tener la necesidad de sobreescribirla denuevo los datos ✏.\n```\n// Spread operator\n\nlet person = {name: 'Alejo', age: 25};\nlet country = 'CO'\n\nlet data = { ...person, country};\n👨‍💻 console.log(data)\n✅ ---\u003e Result: { name: 'Alejo', age: 25, country: 'CO' }\n```\n\n### 💾 Crear copias de objetos utilizando las propiedades de propagación\n\n\u003e 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.\n\u003e De esta manera el segundo objeto tendrá una referencia en memoria diferente al original.\n```\n👨‍🔧 const objetoOriginal = {a: 1, b: 2}\n👨‍🔧 const objetoReferencia = objetoOriginal\n👨‍🔧 const objetoCopia = {...objetoOriginal}\n\n✅ objetoReferencia === objetoOriginal // true\n✅ objetoOriginal === objetoCopia // false\n```\n\u003e El operador de propagación sirve para crear una copia en un solo nivel de profundidad, esto quiere decir que si existen objetos o arrays dentro de un objeto a copiar. Entonces los sub-elementos en cada nivel, tendrán **la misma referencia en la copia y en el original.**\n```\n👨‍🔧 const original = { datos: [1, [2, 3], 4, 5] }\n👨‍🔧 const copia = { ...original }\n\n✅ original === copia // false\n✅ original[\"datos\"] === copia[\"datos\"] // true\n```\n\u003e Forma de dispersar las propiedades utilizando un spreed como param, a esto se le define rest-spreed.\n```\n// Rest-spread\n\n👨‍🔧 function sum(num, ...values){\n    console.log(values);\n    console.log(num + values[0]);\n    return num + values[0];\n}\n\n👨‍💻 sum(1,1,2,3,4)\n✅ ---\u003e Result: [ 1, 2, 3, 4 ] 2 =\u003e retorna: 2\n```\n## 🛠 Object-literals (Mejora a los objetos)\n\u003ePodemos utilizar funciones para que nos devuelvan un objeto con todos los argumentos que les enviamos.\n\n```\n👨‍🔧 function newUser(user, age, country, uId){\n    return {\n        user,\n        age,\n        country,\n        uId\n    }\n}\n\n👨‍💻 console.log(newUser(\"lonper\", 25, \"CO\", 1))\n✅ ---\u003e Result: { user: 'lonper', age: 25, country: 'CO', uId: 1 }\n```\n\n## 🛠 Promises (Algo que va a suceder o no).\n\u003e Las promesas se utilizan como los callbacks, los cuales reciben una funcion como parametro, pero en este caso una promesa nos devolvera el valor apartir de una validacion, lo cual podria ser aceptada o rechazada.\n\n\u003e ✅resolve -\u003e Si fue aceptada la validacion.\n\n\u003e ❌reject -\u003e Si fue rechazada la validacion.\n\n```\n👨‍🔧 const anotherFunction = () =\u003e {\n    return new Promise((resolve,reject) =\u003e {\n        if(true){\n        ✅  resolve('Hey!!')\n        } else {\n        ❌  reject('Whoooops!')\n        }\n    })\n}\n```\n\u003e El metodo 🛬 then nos devuelve el resultado de la funcion 👨‍🔧 anotherFunction().\n```\n👨‍🔧 anotherFunction()\n    .then(response =\u003e console.log(response))\n    .catch(err =\u003e console.log(err));\n\n✅ ---\u003e Result: Hey!!\n```\n## 🛠 Clases (Diseño de clases - Utilizando herencia)\n\u003e Las clases se han utilizado en distintos lenguajes que utilicen la orientacion a objetos, ya que las clases nos permiten utilizar la herencia en diferentes objetos en donde necesitemos cierto elementos instanciados dentro de la estructura de la clase.\n\n```\n//Declarando una clase\n\n👨‍🔧 class User {};\n\n// Instanciando metodos dentro de la clase.\n\n👨‍🔧 class user {\n    //metodos\n    greeting(){\n        return 'Hello';\n    }\n};\n\n// Instanciando objetos y utilizando los metodos de la clase.\n\n⚓ const gndx = new user();\n👨‍💻 console.log(gndx.greeting());\n✅ ---\u003e Result: Hello\n\n⚓ const bebeloper = new user();\n👨‍💻 console.log(bebeloper.greeting());\n✅ ---\u003e Result: Hello\n\n// Utilizando el constructor para inicializar.\n\n👨‍🔧 class user {\n    // Constructor\n    constructor(){\n        console.log('Nuevo Usuario');\n    }\n    greeting(){\n        return 'Hello';\n    }\n}\n\n⚓ const manuel = new user();\n✅ ---\u003e Result: Nuevo Usuario\n```\n### 🏷 This\n\u003e La palabra reservada this, nos sirve como puntero hacia una referencia, en este caso utilizamos this para hacer referencia al elemento padre que contiene la el valor del argumento.\n\n```\n// this \n👨‍🔧 class user {\n    constructor(name){\n        this.name = name; //hace referecnia. \n    }\n    //metodos\n    speak(){\n        return 'Hello';\n    }\n    greeting(){\n        return `${this.speak()} ${this.name}`;\n    }\n}\n\n⚓ const Alejo = new user('Alejo');\n👨‍💻 console.log(Alejo.greeting());\n✅ ---\u003e Result: Hello Alejo\n```\n### ⚖ Getters \u0026 Setters \n\u003e Los metodos Getters \u0026 Setters nos permiten obtener el valor de una variable(Getters) y modificar el valor de las variables(Setters).\n\n```\n👨‍🔧 class user {\n    //constructor\n    constructor(name, age){\n        this.name = name;\n        this.age = age;\n    }\n    // metodos\n    speak(){\n        return 'Hello';\n    }\n    greeting(){\n        return `${this.speak()} ${this.name}}`\n    }\n    // Getter\n    get uAge(){\n        return this.age;\n    }\n    // Setter\n    set uAge(n){\n        this.age = n;\n    }\n}\n\n// Instanciando un nuevo objeto\n⚓ const bebeloper1 = new user('David', 15);\n\n// Llamando al metodo Getter\n👨‍💻 console.log(bebeloper1.uAge);\n✅ --\u003e Result: 15\n\n// Llamando al metodo Setter\n👨‍💻 console.log(bebeloper1.uAge = 24);\n✅ --\u003e Result: 24\n```\n### 🛠 Module (exportar \u0026 importar funciones de diferentes archivos)\n\n\u003e Aveces cuando se quiere obtener un codigo mas limpio y segmentado, no el famoso codigo espagueti, se utilizan modulos los cuales son archivos distintos, en donde estan definidas ciertas funciones que pueden ser requeridas para el desarrollo de un programa.\n\n`📑 $ module.js`\n\n```\n//Se instancia un metodo o funcion en un archivo diferente.\n\n👨‍🔧 const hello = () =\u003e {\n    console.log('Hello!');\n}\n\n//Se exporta el metodo o la funcion del archivo.\n\n🛫 export default hello;\n```\n\n`📑 $ 08-module.js`\n```\n// Se importa los elementos del otro archivos.\n🛬 import hello from \"./module.js\";\n\n// Se ejecuta el metodo importado\n\n👨‍💻 hello();\n✅ ---\u003e Result: Hello!\n```\n\n\u003e Se debe configurar el archivo package.json para poder utilizar un modulo.\n\n`📑 $ package.json`\n```\n{\n  \"name\": \"curso-de-ecmascript\",\n  \"version\": \"1.0.0\",\n  \"description\": \"\",\n  \"main\": \"index.js\",\n  \"scripts\": {\n    \"test\": \"echo \\\"Error: no test specified\\\" \u0026\u0026 exit 1\"\n  },\n  \"keywords\": [\n    \"javascript\",\n    \"ecmascript\"\n  ],\n  \"author\": \"Manuel Perdomo \u003clonperman@gmail.com\u003e\",\n  \"license\": \"MIT\",\n  \"type\": \"module\" // ➕ Se agrega el modulo. \n}\n```\n\n## 🛠 Generadores\n\u003e Los generadores son funciones especiales que pueden pausar su ejecución, luego volver al punto donde se quedaron, recordando su scope y seguir retornando valores.\n\n\u003e Estos se utilizan para guardar la totalidad de datos infinitos, a través de una función matemática a valores futuros. De esta manera ocupan poca memoria, con respecto a si creamos un array u objeto.\n\n### 💡 Cómo utilizar generadores\n\u003e La sintaxis de los generadores comprende lo siguiente:\n\n- La palabra reservada `function*` (con el asterisco al final).\n- La palabra reservada `yield` que hace referencia al valor retornado cada vez que se invoque, recordando el valor anterior.\n- Crear una variable a partir de la función generadora.\n- 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.\n\n\u003e Si el generador se lo invoca y ha retornado todos sus valores de `yield`, entonces devolverá el objeto con las propiedades `value` con `undefined` y un `done` con `true`.\n\n```\n// Declaración\n\n👨‍🔧 function* nombre(parámetros){\n    yield (primer valor retornado)\n    yield (segundo valor retornado)\n    ...\n    yield (último valor retornado)\n\n}\n\n//Crear el generador\n⚓ const generador = nombre(argumentos)\n\n// Invocacioens\n\n✅ generador.next().value //primer valor retornado\n✅ generador.next().value //segundo valor retornado\n...\n✅ generador.next().value //último valor retornado\n```\n### 🔧 Ejemplo de un generador\n\u003e Creamos un generador que retornara tres valores.\n\n```\n👨‍🔧 function* generator(){\n    yield 1\n    yield 2\n    yield 3\n}\n\n⚓ const generador = generator()\n\n✅ generador.next().value //1\n✅ generador.next().value //2\n✅ generador.next().value //3\n✅ generador.next() // {value: undefined, done: true}\n```\n\n### 🔧 Ejemplo utilizando for.\n```\n👨‍🔧 function* iterate(array){\n    for(let value of array){\n        yield value;\n    }\n}\n\n⚓ const it = iterate(['Alejo','Manuel','Nicolas','Camilo'])\n\n// Invocaciones\n\n👨‍💻 console.log(it.next().value) // ✅ Alejo\n👨‍💻 console.log(it.next().value) // ✅ Manuel\n👨‍💻 console.log(it.next().value) // ✅ Nicolas\n```\n## 🛠 Set\n\u003e Set es una nueva estructura de datos para almacenar elementos únicos, es decir, sin elementos repetidos.\n\n### 💡 Como manipular los Sets\n\u003e Para manipular estas estructuras de datos, existen los siguientes métodos:\n\n- `add(value)`: añade un nuevo valor.\n- `delete(value)`: elimina un elemento que contiene el `Set`, retorna un booleano si existía o no el valor.\n- `has(value)`: retorna un booleano si existe o no el valor dentro del `Set`.\n- `celar(value)`: elimina todos los valores del `Set`.\n- `size`: retorna la cantidad de elementos del `Set`.\n\n\n```\n\\\\ 🔨 Se define una instancia.\n\nconst list = new Set();\n\n\\\\ Agregando elementos al elemento Set.\n\n➕ list.add('item 1');\n➕ list.add('item 2').add('item 3');\n\n👨‍💻 console.log(list)\n✅ ---\u003e Result: Set(3) { 'item 1', 'item 2', 'item 3' }\n```\n\n### Como quitar los elementos repetidos.\n```\n// Array con elementos repetidos.\n\n👨‍🔧 const array = [1, 1, 2, 2, 3, 4, 4, 5]\n\n// Creando nuevo array\n\n👨‍🔧 const sinRepetidos = [... new Set(array)]\n\n👨‍💻 console.log(sinRepetidos)\n✅ ---\u003e Result: [ 1, 2, 3, 4, 5 ]\n```\n# ⚙ EcmaScript 7\n\n## 🛠 Exponential\n\u003e El operador de potenciación (exponential operator) consiste en elevar una base a un exponente utilizando el doble asterisco `(**)`.\n\n\u003e `base ** exponente`\n\n```\n👨‍🔧 const data = 3 ** 4;\n👨‍💻 console.log(data);\n✅ ---\u003e Result: 81 \n```\n## 🛠 Includes\n\u003e El método `includes` determina si un array o string incluye un determinado elemento. Devuelve `true` o `false`, si existe o no respectivamente.\n\n```\n// Utilizando arrays.\n\n👨‍🔧 let numbers = [1, 3, 4, 6, 7, 8];\n👨‍💻 console.log(numbers.includes(9));\n✅ ---\u003e Result: false\n\n👨‍🔧 const list = ['Oscar','David','Ana'];\n👨‍💻 console.log(list.includes('Oscar'));\n✅ ---\u003e Result: true\n```\n### Include para objetos.\n\u003e En objetos también existen formas para saber si existe una propiedad.\n\n- La palabra reservada `in`.\n- El metodo de objetos `hasOwnProperty`.\n- El método `Object.hasOwn`, que recibe el objeto y la propiedad a evaluar.\n\n```\n👨‍🔧 const letras = { a: 1, b: 2, c: 3 }\n\n👨‍💻 \"a\" in letras \n✅ ---\u003e Result: true\n👨‍💻 letras.hasOwnProperty(\"a\") \n✅ ---\u003e Result: true\n👨‍💻 Object.hasOwn(letras, \"a\") \n✅ ---\u003e Result: true\n```\n# ⚙ EcmaScript 8\n## 🔧 Object-entries\n\u003e `Object.entries()` devuelve un array con las entries en forma `[propiedad, valor]` del objeto enviado como argumento.\n```\n👨‍🔧 const countries = {MX: 'Mexico', CO: 'Colombia', CL: 'Chile', PE: 'Peru'};\n\n👨‍💻 console.log(Object.entries(countries));\n✅ ---\u003e Result ⬇: \n[\n  [ 'MX', 'Mexico' ],\n  [ 'CO', 'Colombia' ],\n  [ 'CL', 'Chile' ],\n  [ 'PE', 'Peru' ]\n]\n```\n## 🔧 Object-values\n\u003e `Object.values()` devuelve un array con los valores de cada propiedad del objeto enviado como argumento.\n```\n👨‍🔧 const countries = {MX: 'Mexico', CO: 'Colombia', CL: 'Chile', PE: 'Peru'};\n\n👨‍💻 console.log(Object.values(countries));\n✅ ---\u003e Result: [ 'Mexico', 'Colombia', 'Chile', 'Peru' ]\n```\n## 🔧 Object-keys\n\u003e `Object.keys()` devuelve un array con las propiedades `(keys)` del objeto enviado como argumento.\n```\n👨‍🔧 const countries = {MX: 'Mexico', CO: 'Colombia', CL: 'Chile', PE: 'Peru'};\n\n👨‍💻 console.log(Object.keys(countries));\n✅ ---\u003e Result: [ 'MX', 'CO', 'CL', 'PE' ]\n```\n## 🛠 String padding\n\u003e El padding consiste en rellenar un `string` por el principio o por el final, con el carácter especificado, repetido hasta que complete la longitud máxima.\n\n\u003e Este método recibe dos argumentos:\n\n- La longitud máxima a rellenar, incluyendo el `string` inicial.\n- El `string` para rellenar, por defecto, es un espacio.\n\n\u003e Si la longitud a rellenar es menor que la longitud del string actual, entonces no agregará nada.\n\n### 🛠 Metodos\n#### 🔧 Metodo padStart\n\u003e El método `padStart` completa un `string` con otro `string` en el inicio hasta tener un total de caracteres especificado.\n```\n👨‍🔧 const string = 'Hello';\n\n👨‍💻 console.log(string.padStart(6,'_'));\n✅ ---\u003e Result: _Hello\n\n👨‍💻 console.log(string.padStart(10,'foo'));\n✅ ---\u003e Result: foofoHello\n\n👨‍💻 console.log(string.padStart(6,'123456'));\n✅ ---\u003e Result: 123Hello\n```\n### 🔧 Metodo padEnd\n\u003e El método padEnd completa un string con otro string en el final hasta tener un total de caracteres especificado.\n```\n👨‍🔧 const string = 'Hello';\n👨‍💻 console.log(string.padEnd(8,'123456'));\n✅ ---\u003e Result: Hello123\n\n👨‍💻 console.log(string.padEnd(10,'123456'));\n✅ ---\u003e Result: Hello12345\n\n👨‍💻 console.log(string.padEnd(6,'123456'));\n✅ ---\u003e Result: Hello1\n```\n## 🛠 Trailing commas\n\u003e Las trailing commas consisten en comas al final de objetos o arrays que faciliten añadir nuevos elementos y evitar errores de sintaxis.\n```\n👨‍🔧 const array = [24,34,25,26,,,,45]; //📢 Trailing commas\n\n👨‍💻 console.log(array);\n✅ ---\u003e Result: [ 24, 34, 25, 26, \u003c3 empty items\u003e, 45 ]\n👨‍💻 console.log(array.length);\n✅ ---\u003e Result: 8\n```\n\n## 🛠 Funciones asíncronas\n\u003e Es otra forma de ejecutar funciones, pero esta presente una particularidad, ya que se ejecutara la funcion pero al utilizar `await` en una proemsa la funcion que tiene el `async` estara pendiente de la respuesta que le devuelva.\n\n### 🔧 Como utilizar funciones asíncronas\n\u003e La función asíncrona se crea mediante la palabra reservada `async` y retorna una promesa.\n```\n👨‍🔧 async function asyncFunction () {...}\n\n👨‍🔧 const asyncFunction = async () =\u003e { ... } \n```\n\u003e La palabra reservada await significa que espera hasta que una promesa sea resuelta y solo funciona dentro de una función asíncrona. Los bloques try / catch sirven para manejar si la promesa ha sido resuelta o rechazada.\n\n```\n👨‍🔧 async function asyncFunction () {\n  try {\n    const response = await promesa()\n    return response\n  } catch (error) {\n    return error\n  }\n}\n```\n\u003e ¿Cuál es la mejor forma de manejar promesas, then o async / await? Ambas son muy útiles, manejar ambas te hará un mejor desarrollador.\n\n### 👨‍💻 Ejemplo Async-Await\n```\n👨‍🔧 const fnAsync = () =\u003e {\n    return new Promise((resolve, reject) =\u003e {\n        (true) \n            ? setTimeout(() =\u003e resolve('AsynC'),2000) \n            : reject(new Error('Error!'));\n    });\n}\n\n👨‍🔧 const anotherFn = async () =\u003e {\n ⏳ const somethig = await fnAsync();\n    console.log(somethig);\n    console.log('Hello!');\n}\n\n👨‍💻 anotherFn();\n✅ ---\u003e Result: AsynC Hello!\n```\n# ⚙ EcmaScript 9\n## 🛠 Expresiones regulares\n\u003e Las expresiones regulares o RegEx (regular expresions) son **patrones de búsqueda y manipulación de cadenas de caracteres** increíblemente potente y están presentes en todos los lenguajes de programación.\n\u003e En JavaScript se crea este patrón entre barras inclinadas (/patrón/) y se utiliza métodos para hacer coincidir la búsqueda.\n```\n👨‍🔧 const regex = /(\\d{4})-(\\d{2})-(\\d{2})/;\n👨‍💻 const matchers = regex.exec('2022-01-01')\n👨‍💻 console.table(matchers);\n✅ ---\u003e Result: \n┌─────────┬──────────────┐\n│ (index) │    Values    │\n├─────────┼──────────────┤\n│    0    │ '2022-01-01' │\n│    1    │    '2022'    │\n│    2    │     '01'     │\n│    3    │     '01'     │\n│  index  │      0       │\n│  input  │ '2022-01-01' │\n│ groups  │  undefined   │\n└─────────┴──────────────┘\n```\n## 🛠 Método finally en promesas\n\u003e El método `finally` para promesas consiste en ejecutar código después que una promesa haya sido ejecutada como resuelta o rechazada.\n```\n👨‍🔧 promesa()\n    .then(response =\u003e console.log(response) //✅ Promesa resuelta\n    .catch(error =\u003e console.log(response) //✅ Promesa rechazada\n    .finally( () =\u003e console.log(\"Finalizado\") ) //✅ Código final  \n```\n## 🛠 Generadores asíncronos\n\u003e Los generados asíncronos son semejantes a los generadores que ya conoces, pero combinando sintáxis de promesas.\n```\n👨‍🔧 async function* anotherGenerator(){\n    yield await Promise.resolve(1);\n    yield await Promise.resolve(2);\n    yield await Promise.resolve(3);\n}\n\n👨‍🔧 const other = anotherGenerator();\n👨‍💻 other.next().then(response =\u003e console.log(response.value));\n👨‍💻 other.next().then(response =\u003e console.log(response.value));\n👨‍💻 other.next().then(response =\u003e console.log(response.value));\n👨‍💻 console.log('Hello!')\n✅ ---\u003e Result: 🔽\n                Hello!\n                1\n                2\n                3\n```\n### Cómo utilizar for await\n\u003e De la misma manera, `for await` es un ciclo repetitivo que se maneja asíncronamente. El ciclo siempre debe estar dentro de una función con `async`.\n```\n👨‍🔧 async function forAwait() {\n  const nombres = [\"Alexa\", \"Oscar\", \"David\"]\n  for await (let valor of nombres) {\n    console.log(valor)\n  }\n}\n\n👨‍💻 forAwait()\n✅ ---\u003e Result: 🔽\n                Alexa\n                Oscar\n                David\n```\n# ⚙ EcmaScript 10\n## 🛠 flat-map y trimStart-trimEnd\n### 💡 Qué es el aplanamiento de arrays\n\u003e El aplanamiento consiste en transformar un array de arrays a una sola dimensión. Los métodos `flat` y `flatMap` permitirán realizar el aplanamiento.\n\n### 🔧 Metodo flat\n\u003e El método flat devuelve un array donde los sub-arrays han sido propagados hasta una profundidad especificada.\n\n\u003e Este método es inmutable, es decir, retorna un nuevo array con los cambios y no cambia el array original.\n\n\u003e Este método recibe un argumento:\n\n- La profundidad del aplanamiento, por defecto, tiene un valor de 1.\n\n\u003e Si se desea aplanar todos los sub-arrays en una sola dimensión, utiliza el valor de `Infinity`.\n```\n👨‍🔧 const array = [1,2,[3,4],5,6]\n👨‍💻 const result = array.flat() \n✅ ---\u003e result: [1,2,3,4,5,6]\n\n👨‍🔧 const array2 = [1, 2, [3, 4, [5, 6]]];\n👨‍💻 const result2 = array2.flat() \n✅ ---\u003e result2: [1, 2, 3, 4, [5, 6]]\n\n👨‍🔧 const array3 = [1, 2, [3, 4, [5, 6]]]\n👨‍💻 const result3 = array3.flat(2) \n✅ ---\u003e result3: [1, 2, 3, 4, 5, 6]\n\n👨‍🔧 const array4 = [1, 2, [3, 4, [5, 6, [7, 8, [9, 10]]]]]\n👨‍💻 const result4 = array4.flat(Infinity) \n✅ ---\u003e result4: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n```\n### 🔧 Método flatMap\n\u003e El método `flatMap` es una combinación de los métodos `map` y `flat`. Primero realiza la iteración de los elementos del `array` (como si fuera `map`), y después los aplana en una sola profundidad (como si fuera `flat`).\n\n\u003e Este método es inmutable, es decir, retorna un nuevo array con los cambios y no cambia el array original.\n\n\u003e Este método recibe los mismos argumentos que el método map.\n```\n👨‍🔧 const strings = [\"Nunca pares\", \"de Aprender\"]\n👨‍💻 strings.map(string =\u003e string.split(\" \")) \n✅ ---\u003e Result: [ [ 'Nunca', 'pares' ], [ 'de', 'Aprender' ] ]\n👨‍💻 strings.flatMap(string =\u003e string.split(\" \")) \n✅ ---\u003e Result: [ 'Nunca', 'pares', 'de', 'Aprender' ]\n\n👨‍🔧 const numbers = [1,2, 3, 4]\n👨‍💻 numbers.map(number =\u003e [number * 2]) \n✅ ---\u003e Result: [[2], [4], [6], [8]]\n👨‍💻 numbers.flatMap(number =\u003e [number *2]) \n✅ ---\u003e Result: [2, 4, 6, 8]\n\n📢 Cuidado, primero hace el map y luego el flat\n👨‍🔧 const numbers2 = [1,[2,3], 4, 5]\n👨‍💻 numbers2.flatMap(number =\u003e [number *2]) \n✅ ---\u003e Result: [ 2, NaN, 8, 10 ]\n```\n### 🧹 Eliminar espacios en blanco de un string\n\u003e Existen tres métodos para eliminar espacios en blanco de un string:\n\n- El método `trim` elimina los espacios en blanco al **inicio y al final**.\n- El método `trimStart` o `trimLeft` elimina los espacios al **inicio**.\n- El método `trimEnd` o `trimRight` elimina los espacios al **final**.\n```\n👨‍🔧 const saludo = \"      hola      \"\n👨‍💻 const result1 = saludo.trim()\n👨‍💻 const result2 = saludo.trimStart()\n👨‍💻 const result3 = saludo.trimEnd()\n\n✅ ---\u003e result1: 'hola'\n✅ ---\u003e result2: 'hola      '\n✅ ---\u003e result3: '      hola'\n```\n## 🛠 try catch y fromEntries\n### 🔧 Parámetro opcional de catch\n\u003e El parámetro opcional de `catch` permite omitir el error si es necesario.\n```\ntry {\n  // 📢 Manejar el código\n} catch (err) {\n  // 💡 Se utiliza el parámetro `err`\n}\n\ntry {\n  // 📢 Manejar el código\n} catch {\n  // 💡 Manejar el error sin el parámetro.\n}\n```\n\u003e 💡 Aunque siempre es recomendable manejar el error como parámetro, ya que tiene más información del problema.\n\n### 🔧 Cómo transformar un array de arrays en un objeto.\n\n\u003e El método `Object.fromEntries` devuelve un objeto a partir de un array donde sus elementos son las entries en forma `[propiedad, valor]`.\n\n\u003e Se considera la operación inversa de `Object.entries()`.\n```\n👨‍🔧 const arrayEntries = [\n  [ 'name', 'Manuel' ],\n  [ 'email', 'lonper@correo.com' ],\n  [ 'age', 25 ]\n] \n\n👨‍💻 const usuario = Object.fromEntries(arrayEntries) \n\n👨‍💻 console.log(usuario)\n✅ ---\u003e Result: { name: 'Manuel', email: 'lonper@correo.com', age: 25 }\n```\n# ⚙ EcmaScript 11\n## 🛠 Optional chaining\n\u003e Cuando intentas acceder a propiedades de un objeto que no existen, JavaScript te retornará `undefined`.\n```\n👨‍🔧 const usuario = {}\n👨‍💻 console.log(usuario.redes)\n❌ ----\u003e Result: undefined\n```\n\u003e 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 de tipo.\n```\n👨‍🔧 const usuario = {}\n👨‍💻 console.log(usuario.redes.facebook) \n❌ ---\u003e TypeError: Cannot read properties of undefined (reading 'facebook')\n```\n\u003e Es como intentar ejecutar `undefined.facebook`, lo cual es un error de tipo, debido a que `undefined` es un primitivo, no es un objeto.\n### 💡🔧 Cómo utilizar el encadenamiento opcional\n\u003e El encadenamiento opcional u optional chaining `(?.)` detiene la evaluación del objeto cuando el valor es `undefined` o `null` antes del `(?.)`, retornando `undefined` sin detener el programa por un error.\n```\n👨‍🔧 const usuario = {}\n👨‍💻 console.log(usuario.redes?.facebook) \n✅ ---\u003e Result: undefined\n```\n\u003e 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.\n### 💡 No abuses del encadenamiento opcional\n\u003e **El encadenamiento opcional se debe utilizar únicamente cuando probablemente un valor no exista.**\n\u003e 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`.\n\n\u003e Si abusas del encadenamiento opcional y existe un error en un objeto, el programa podría **“ocultarlo”** por un `undefined`, provocando que el debugging sea más complicado.\n\n## 🛠 BigInt y Nullish\n### 🔧 Big Int, enteros muy grandes\n\u003e El nuevo 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`.\n```\n👨‍🔧 const number1 = 45n\n👨‍🔧 const number2 = BigInt(45)\n\n👨‍💻 console.log(typeof 45n) \n✅ ---\u003e Result: 'bigint'\n```\n\u003e JavaScript tiene límites numéricos, un máximo `Number.MAX_SAFE_INTEGER` y un mínimo `Number.MIN_SAFE_INTEGER`.\n\n```\n👨‍🔧 const max = Number.MAX_SAFE_INTEGER\n👨‍🔧 const min = Number.MIN_SAFE_INTEGER\n\n👨‍💻 console.log(max)  ✅ ---\u003e Result: 9007199254740991\n👨‍💻 console.log(min)  ✅ ---\u003e Result: -9007199254740991\n```\n\u003e **Después de los límites, los cálculos muestran resultados erróneos**. Los `bigint` ayudan a manejar operaciones de enteros fuera de los límites mencionados.\n```\n👨‍🔧 const increment = 2\n👨‍🔧 const number = Number.MAX_SAFE_INTEGER + increment\n👨‍🔧 const bigInt = BigInt(Number.MAX_SAFE_INTEGER) + BigInt(increment)\n\n👨‍💻 console.log(number) ✅ ---\u003e Result: 9007199254740992\n👨‍💻 console.log(bigInt) ✅ ---\u003e Result: 9007199254740993n\n```\n\u003e Se añade la misma cantidad a ambos tipos de datos, sin embargo, el tipo numérico da un resultado diferente al esperado.\n\n### 🔧 Operador Nullish Coalescing\n\u003e El operador nullish coalescing (`??`) consiste en evaluar una variable si es `undefined` o `null` para asignarle un valor.\n\n\u003e El siguiente ejemplo se lee como: `¿usuario.name` es `undefined` o `null`? Si es así, asígnale un valor por defecto `\"Alejo\"`, caso contrario asigna el valor de `usuario.name`.\n```\n👨‍🔧 const usuario1 = {}\n👨‍💻 const nombre1 = usuario1.name ?? \"Alejo\"\n\n👨‍🔧 const usuario2 = {name: \"Nicolas\"}\n👨‍💻 const nombre2 = usuario2.name ?? \"Alejo\"\n\n👨‍💻 console.log(nombre1) ✅ ---\u003e Result: 'Alejo' \n👨‍💻 console.log(nombre2) ✅ ---\u003e Result: 'Nicolas'\n```\n### 💡 Diferencia entre el operador OR y el Nullish coalescing\n\n\u003e El operador OR (`||`) **evalúa un valor falsey**. Un valor falsy es aquel que es falso en un contexto booleano, estos son: `0`, `\"\"` (string vacío), `false`, `NaN`, `undefined` o `null`.\n\n\u003e Puede que recibas una variable con un valor falsy que necesites 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.\n```\n👨‍🔧 const id = 0\n\n👨‍🔧 const orId = id || \"Sin id\"\n👨‍🔧 const nullishId = id ?? \"Sin id\"\n\n👨‍💻 console.log( orId ) ❌ ---\u003e Result: 'Sin id'\n👨‍💻 console.log( nullishId ) ✅ ---\u003e Result: 0\n```\n## 🛠 Promise.allSettled\n\u003e En alguna situación necesitarás manejar varias **promesas** y obtener sus resultados. ¿Cómo? Utilizando los métodos `Promise.all` y `Promise.allSettled`.\n\n### 🔧 Promise.all\n\u003e El método `Promise.all` sirve para manejar varias promesas al mismo tiempo. Recibe como argumento un array de promesas.\n```\n👨‍🔧 Promise.all([promesa1, promesa2, promesa3])\n        .then(respuesta =\u003e console.log(respuesta))\n        .catch(error =\u003e console.log(error))\n```\n\u003e El problema es que `Promise.all()` se resolverá, si y solo si **todas las promesas fueron resueltas**. Si al menos una promesa es rechazada, `Promise.all` será rechazada.\n\n### 🔧 Promise.allSettled\n\u003e `Promise.allSettled()` permite manejar varias promesas, que devolverá un array de objetos con el **estado y el valor de cada promesa, haya sido resuelta o rechazada**.\n\n```\n👨‍🔧 const promise1 = new Promise((resolve, reject) =\u003e reject(\"Rechazada\"));\n👨‍🔧 const promise2 = new Promise((resolve, reject) =\u003e resolve(\"Resuelta\"));\n👨‍🔧 const promise3 = new Promise((resolve, reject) =\u003e resolve(\"Resuelta 2\"));\n\n👨‍💻 Promise.allSettled([promise1, promise2, promise3])\n        .then(response =\u003e console.log(response));\n\n✅ ---\u003e Result:\n    [\n        { status: 'rejected', reason: 'Rechazada' },\n        { status: 'fulfilled', value: 'Resuelta' },\n        { status: 'fulfilled', value: 'Resuelta 2' }\n    ]\n```\n\u003e ¿Debería usar `Promise.allSettled` en lugar de `Promise.all`? No, porque ambas son muy útiles dependiendo cómo quieras **manejar tus promesas**.\n\n## 🛠 globalThis y matchAll.\n### 🔧 Objeto global para cualquier plataforma\n\u003e El motor de JavaScript, aquel que compila tu archivo y lo convierte en código que entiende el computador, **al iniciar la compilación crea un objeto global**.\n\n\u003e **El 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.\n\n\u003e 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`.\n\n\u003e Para estandarizar el objeto global se creó `globalThis`, un objeto compatible para cualquier plataforma.\n\n```\n// Ejecuta el siguiente código y observa que muestra\n👨‍💻 console.log(window) ❌\n👨‍💻 console.log(globalThis) ✅\n\n// En el navegador\nwindow === globalThis ✅ ---\u003e Result: true\n\n// En Node.js\nglobal === globalThis ✅ ---\u003e Result: true\n```\n## 🛠 Método `matchAll` para expresiones regulares.\n\u003e El método `matchAll` de los strings **devuelve un iterable** con todas las coincidencias del string específico a partir de una expresión regular, colocada como argumento.\n- `string.matchAll(regex)`\n\u003e En el iterable, existe una propiedad denominada `index` con el índice del string donde la búsqueda coincide.\n\n```\n🔧 const regex = /\\b(Apple)+\\b/g\n\n👨‍🔧 const fruit = \"Apple, Banana, Kiwi, Apple, Orange, etc. etc. etc.\"\n\n// Tranformación del iterable retornado a array\n👨‍💻 const array = [...fruit.matchAll(regex)]\n📢 console.log(array)\n✅ ---\u003e Result:\n    [\n        [\n            'Apple',\n            'Apple',\n            index: 0,\n            input: 'Apple, Banana, Kiwi, Apple, Orange, etc. etc. etc.',\n            groups: undefined\n        ],\n        [\n            'Apple',\n            'Apple',\n            index: 21,\n            input: 'Apple, Banana, Kiwi, Apple, Orange, etc. etc. etc.',\n            groups: undefined\n        ]\n    ]\n```\n## 🛠 Dynamic Import\n\u003e La expresión `import()` permite manejar módulos dinámicamente, ya que la sintaxis de ECMAScript `import ... from ...` no lo permite.\n\n### Cómo utilizar importación dinámica.\n\u003e La **importación dinámica** consiste en cargar los módulos cuando el usuario los vaya a utilizar, y no al iniciar la aplicación. Esto permite que la página web sea más rápida, porque descarga menos recursos.\n\n\u003e La expresión `import()` recibe un argumento de tipo `string` con la ruta del módulo a importar y devuelve una promesa.\n```\n🛣 const ruta = \"./modulo.js\"\n\n// Utilizando promesas\n🛬  import(ruta)\n        .then( modulo =\u003e {\n        📢 modulo.funcion1()\n        📢 modulo.funcion2()\n        })\n        .catch(error =\u003e console.log(error))\n    \n// Utilizando async/await\n⏳  async function importarModulo(rutaDelModulo) {\n    🛬  const modulo = await import(rutaDelModulo)\n    📢  modulo.funcion1()\n    📢  modulo.funcion2()\n    }\n\n👨‍💻 importarModulo(ruta)\n```\n## 💡 Ejemplo utilizando importación dinámica.\n\u003e De esta manera puedes utilizar una importación dinámica en tu aplicación para desencadenar una descarga de un módulo cuando el usuario lo vaya a utilizar. Por ejemplo, al realizar clic en un botón.\n```\n🔎 const boton = document.getElementById(\"boton\")\n\n👂  boton.addEventListener(\"click\", async function () {\n        const modulo = await import('./modulo.js')\n        modulo.funcion()\n    })\n```\n\u003e Puedes usar **las herramientas de desarrollador** para visualizar la descarga de archivos al realizar clic en el botón.\n\n# ⚙ EcmaScript 12\n## 🛠 numeric-separators y replaceAll\n### 🔧 Separadores numéricos\n\u003e Los separadores numéricos ayudan a la legibilidad de cantidades con varias cifras. Se utiliza el caracter guion bajo (` _` ) para **separar las cifras**, y no afecta a la ejecución del programa.\n\n\u003e Lo ideal es separar cada 3 cifras, para visualizar los miles, millones, billones, etc.\n\n```\n// 🔽 Baja legibilidad\n👨‍🔧 const numero1 = 3501548945\n👨‍💻 console.log( numero1 ) \n✅ ---\u003e Result: 3501548945\n\n// ✅ Alta legibilidad\n👨‍🔧 const numero2 = 3_501_548_945\n👨‍💻 console.log( numero2 ) \n✅ ---\u003e Result: 3501548945\n```\n### 🔧 Método replaceAll\n\u003e El método `replaceAll` retorna un nuevo string, reemplazando **todos los elementos por otro**.\n\n\u003e Este método recibe dos argumentos:\n- El **patrón a reemplazar**, puede ser un string o una expresión regular.\n- El **nuevo elemento** que sustituye al reemplazado.\n\n\u003e Este procedimiento fue creado para solucionar el problema que tenía el método `replace`, que realizaba la misma función de reemplazar elementos, pero solamente **una sola vez** por invocación.\n\n```\n👨‍🔧 const mensaje = \"JavaScript es maravilloso, con JavaScript puedo crear el futuro de la web.\"\n\n👨‍💻 mensaje.replace(\"JavaScript\", \"Python\")\n✅ ---\u003e Result: 'Python es maravilloso, con JavaScript puedo crear el futuro de la web.'\n\n👨‍💻 mensaje.replaceAll(\"JavaScript\", \"Python\")\n✅ ---\u003e Result: 'Python es maravilloso, con Python puedo crear el futuro de la web.'\n\n👨‍💻 mensaje.replaceAll(/a/g, \"*\")\n✅ ---\u003e Result: 'J*v*Script es m*r*villoso, con J*v*Script puedo cre*r el futuro de l* web.'\n```\n## 🛠 promise-any y métodos privados.\n### 🔧 Promise.any\n\u003e `Promise.any()` es otra forma de manejar varias promesas, que **retornará la primera promesa que sea resuelta** y rebotará si todas las promesas son rechazadas.\n\n```\n👨‍🔧 const promesa1 = Promise.reject(\"Ups promesa 1 falló\")\n👨‍🔧 const promesa2 = Promise.reject(\"Ups promesa 2 falló\")\n👨‍🔧 const promesa3 = Promise.resolve(\"Promesa 3\")\n\n\n👨‍💻  Promise.any([promesa1, promesa2, promesa3])\n    ✅  .then(respuesta =\u003e console.log(respuesta)) \n    ❌  .catch(error =\u003e console.log(error))\n```\n### 🔧 Métodos privados de clases.\n\u003e Los métodos privados consiste en **limitar el acceso a propiedades y métodos** agregando el caracter numeral `( #)`. Por defecto, las propiedades y métodos de una clase en JavaScript son públicas, es decir, se puede acceder a ellos fuera de la clase.\n\n```\n👨‍🔧  class Clase {\n    👮‍♂️  #private(valor){\n            console.log(valor)\n        }\n        \n    👷‍♂️  public(valor){\n            console.log(valor)\n        }\n    }\n\n🔨 const clase = new Clase()\n👨‍💻 clase.public(\"Hola\")  ✅ ---\u003e Result: 'Hola'\n👨‍💻 clase.private(\"Hola\") ❌ ---\u003e Result: TypeError: clase.private is not a function\n```\n# ⚙ EcmaScript 13.\n## 🛠 at\n\u003e El método `at` de arrays sirve para acceder a los elementos a partir del índice.\n- `array.at(índice)`\n### 💡 Índices positivos y negativos en arrays\n\u003e Los índices positivos comienzan desde `0` hasta la longitud total menos uno, de **izquierda a derecha** del array. El índice `0` es la primera posición.\n\n```\n[0,1,2,3, ...., lenght-1]\n```\n\u003e Los índices negativos comienzan desde `-1` hasta el negativo de la longitud total del array, de **derecha a izquierda**. El índice `-1` es la última posición.\n```\n[-lenght, ...,  -3, -2, -1]\n```\n### 🔧 Cómo utilizar el método `at`.\n\u003e 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.\n```\n👨‍🔧 const nombres = [\"Andres\", \"Valeria\", \"Ana\", \"Ramiro\", \"Richard\"]\n\n👨‍💻 nombres.at(-1) ✅ ---\u003e \"Richard\"\n👨‍💻 nombres[-1] ❌ ---\u003e undefined\n👨‍💻 nombres.at(-3) ✅ ---\u003e \"Ana\"\n👨‍💻 nombres[nombres.length -1] ✅ ---\u003e \"Richard\"\n```\n## 🛠 top level await en el consumo de una API.\n\u003e Top level await 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.\n\n### 🔧 Cómo utilizar top level await.\n\u003e Anterior a ECMAScript 13, cuando se introdujo funciones asíncronas, si utilizabas `await` fuera de `async`, existirá un error de sintáxis.\n```\n// ❌ Error\nawait fetch(URL)\n❌ ---\u003e Result: SyntaxError: await is only valid in async function\n```\n\u003e 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.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flonperman%2FCurso-EcmaScript","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flonperman%2FCurso-EcmaScript","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flonperman%2FCurso-EcmaScript/lists"}