• Что бы вступить в ряды "Принятый кодер" Вам нужно:
    Написать 10 полезных сообщений или тем и Получить 10 симпатий.
    Для того кто не хочет терять время,может пожертвовать средства для поддержки сервеса, и вступить в ряды VIP на месяц, дополнительная информация в лс.

  • Пользаватели которые будут спамить, уходят в бан без предупреждения. Спам сообщения определяется администрацией и модератором.

  • Гость, Что бы Вы хотели увидеть на нашем Форуме? Изложить свои идеи и пожелания по улучшению форума Вы можете поделиться с нами здесь. ----> Перейдите сюда
  • Все пользователи не прошедшие проверку электронной почты будут заблокированы. Все вопросы с разблокировкой обращайтесь по адресу электронной почте : info@guardianelinks.com . Не пришло сообщение о проверке или о сбросе также сообщите нам.

JavaScript - ES9 (ECMAScript 2018) - Parte I

Lomanu4 Оффлайн

Lomanu4

Команда форума
Администратор
Регистрация
1 Мар 2015
Сообщения
1,481
Баллы
155
Temario

  • Introducción
  • Nuevas Características
    • Rest y Spread Properties para Objetos
    • Asynchronous Iteration (for await…of)
    • Promise.prototype.finally
i. Introducción


Vamos a ver la primera parte de novedades que nos trae la edición ES9 (ES2018) de JavaScript.

Ten en cuenta que no todos los navegadores modernos admiten de forma nativa todas las funcionalidades “nuevas” de JavaScript.

Antes de utilizar alguna de ellas en entornos productivos, verifica la compatibilidad en los navegadores objetivo.

Si estás utilizando un transpilador como Babel o algún sistema de build moderno (por ejemplo, Vite, Webpack con configuración adecuada o Next.js con configuración predeterminada), no deberías preocuparte, ya que estas herramientas se encargan de transpilar el código a versiones compatibles con navegadores más antiguos.

Aunque la mayoría de estas funcionalidades ya cuentan con un amplio soporte en los navegadores actuales, siempre es recomendable hacer una validación explícita antes de lanzar a producción.
ii. Nuevas Características

01. Rest [

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

] y Spread [

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

] Properties para Objetos



Desde ECMAScript 2015 (ES6), la sintaxis ... ya se utilizaba ampliamente en JavaScript para trabajar con arreglos:

  • ...spread: para copiar o combinar arrays.
  • ...rest: para capturar elementos restantes al desestructurar.

const arr = [1, 2, 3];

// Spread: copia propiedades
const newArr = [...arr, 4];
console.log(newArr); // [1, 2, 3, 4]

// Rest: extrae las propiedades
const [first, ...rest] = arr;
console.log(first); // 1
console.log(rest); // [2, 3]

Sin embargo, esta sintaxis no era compatible con objetos, lo que forzaba a los desarrolladores a usar métodos como Object.assign() para copiar, clonar o fusionar objetos.

ECMAScript 2018 vino a resolver esto al extender la capacidad de ...rest y ...spread a objetos, con una sintaxis similar pero adaptada para trabajar con claves y valores. Esto permite:

  • Extraer propiedades restantes de un objeto (rest).
  • Clonar o combinar objetos (spread).

Principales características —

  • Sintaxis limpia y declarativa para operaciones comunes con objetos.
  • Funciona con propiedades enumerables propias (own enumerable).
  • Compatible con desestructuración y funciones.

Ventajas —

  • Reemplaza la necesidad de Object.assign para copias superficiales.
  • Permite evitar mutaciones accidentales.
  • Mejora la legibilidad y expresividad del código moderno.

¿Dónde se usa? —

  • Filtrar un dato antes de enviar a una API (si no es necesario).
  • Separar datos para audit logs o sistemas de monitoreo.
  • Configuración de aplicaciones (theme, locale, features, etc.).
  • Formularios donde el usuario modifica los valores por defecto.
  • Composición de props en React.

Sintaxis —


const obj1 = { a: 1, b: 2 };

// Spread: copia propiedades de obj
const obj2 = { ...obj1, c: 3 };
console.log(obj2); // { a: 1, b: 2, c: 3 }

// Rest: extrae las propiedades restantes
const { a, ...rest } = obj2;
console.log(a); // 1
console.log(rest); // { b: 2, c: 3 }

¿Cómo funciona internamente? —

Durante la desestructuración:

  • El motor recopila las propiedades no extraídas en un nuevo objeto ([[Rest]]).
  • Spread es una forma sintáctica de llamar internamente a Object.assign({}, ...) con preservación del orden.

Ejemplo 1 — Desestructuración con rest


const obj = { x: 1, y: 2, z: 3 };
const { x, ...rest } = obj;

console.log(x); // 1
console.log(rest); // { y: 2, z: 3 }

Donde:

  • const { x, ...rest } = obj; toma la propiedad x y crea una nueva variable llamada rest que contiene todas las propiedades restantes del objeto original.
  • En este caso, rest es un nuevo objeto { y: 2, z: 3 }.
Útil cuando: Deseas acceder a una o dos propiedades específicas y pasar el resto a otro componente, función o API.
Ejemplo 2 — Desestructuración desde los params de la función


function logUser({ id, ...userInfo }) {
console.log('ID:', id); // ID: 42
console.log('Datos:', userInfo); // Datos: { name: 'Mauricio', role: 'user' }
// ...
}

logUser({ id: 42, name: 'Mauricio', role: 'user' });

Donde: Desestructuramos el objeto para extraer id y dejamos el resto (name, role) dentro de userInfo.

Útil cuando: Deseas separar identificadores o metadatos de los datos operativos.
Ejemplo 3 — Overriding de configuraciones


const defaults = { theme: 'dark', layout: 'grid' };
const userSettings = { layout: 'list' };

const finalConfig = { ...defaults, ...userSettings };
console.log(finalConfig); // { theme: 'dark', layout: 'list' }

Donde:

  • Se combinan dos objetos (defaults y userSettings) con spread.
  • Las propiedades del segundo (userSettings) sobrescriben las del primero si coinciden.

Ejemplo 4 — React: Composición de props con spread


function Button(props) {
const { children, ...rest } = props;
return <button {...rest}>{children}</button>;
}

// Uso:
<Button className="btn-primary" onClick={handleClick}>
Guardar
</Button>

Donde: Separamos children para controlarlo, y propagamos el resto (className, onClick, etc.).

Útil ya que: Es un patrón común en componentes reutilizables para no “re-declarar” cada prop.
Ejemplo 5 — Filtrado de campos sensibles


function removeSensitiveFields(user) {
const { password, ssn, ...safeData } = user;
return safeData;
}

const sanitized = removeSensitiveFields({
name: 'John',
email: 'john@example.com',
password: '123456',
ssn: '999-99-9999',
});

console.log(sanitized); // { name: 'John', email: 'john@example.com' }

Donde: Antes de mostrar o guardar el objeto en logs, se eliminan campos sensibles con rest.

Ejemplo 6 — Merging de resultados API + locale override


const apiResponse = {
title: 'Avengers',
description: 'Superhero movie',
rating: 8.7,
};

const localeOverrides = {
title: 'Los Vengadores',
};

const finalData = { ...apiResponse, ...localeOverrides };
// { title: 'Los Vengadores', description: 'Superhero movie', rating: 8.7 }

Donde: Usamos spread para adaptar el contenido a distintos idiomas o preferencias sin modificar el resultado original.

Riesgos comunes —

Ejemplo 1— Spread no aplica como copia profunda



const original = {
user: {
name: 'Mauricio',
age: 40,
},
active: true,
};

// "Clonamos"
const copy = { ...original };

// Modificamos una propiedad del objeto anidado
copy.user.age = 55;

console.log(copy.user.age); // 55
console.log(original.user.age); // 55 - también cambió el original!!!

Aunque copy parece una copia nueva de original, la propiedad user sigue siendo la misma referencia en ambos objetos. Esto ocurre porque ...original solo hace shallow copy, es decir:

  • Copia propiedades de primer nivel (clave/valor).
  • Si ese valor es un objeto, la referencia se copia, no el contenido.

Si necesitas una copia profunda (deep copy), debes usar una estrategia adicional como:


const deepCopy = JSON.parse(JSON.stringify(original));

deepCopy.user.age = 55;

console.log(deepCopy.user.age); // 55
console.log(original.user.age); // 40

Ejemplo 2—rest no aplica como copia profunda


const original = {
user: {
name: 'Angie',
age: 35,
},
active: true,
};

// Usamos rest para separar propiedades
const { active, ...rest } = original;

// Modificamos el objeto anidado en `rest`
rest.user.age = 21;

console.log(rest.user.age); // 21
console.log(original.user.age); // 21 - también cambió el original!!!
  • El operador ...rest creó un nuevo objeto con todas las propiedades excepto active.
  • Sin embargo, la propiedad user dentro de rest sigue siendo la misma referencia que en original.

Si deseas evitar ese riesgo, deberías hacer una deep copy manual o asistida:


const { active, ...rest } = original;
const safeRest = {
...rest,
user: { ...rest.user }, // copia anidada
};

safeRest.user.age = 21;

console.log(safeRest.user.age); // 21
console.log(original.user.age); // 35

Soporte —


A considerar —

  • No hace copia profunda (shallow copy).
  • Solo propiedades propias, no del prototipo.
  • Si hay propiedades repetidas, la última sobrescribe.
  • Usa spread/rest con precaución: no reemplaza lógica de validación profunda.
02. Asynchronous Iteration (for await...of) [

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

]



for await...of permite iterar asincrónicamente sobre objetos async iterables (como streams, APIs paginadas, generadores async, etc.).

Principales características —


Ventajas —

  • Facilita el trabajo con flujos de datos asincrónicos.
  • Código más limpio comparado con .then() o forEach + async.

Sintaxis —


async function process() {
const asyncIterable = {
async *[Symbol.asyncIterator]() {
yield "uno";
yield "dos";
yield "tres";
},
};

for await (const val of asyncIterable) {
console.log(val);
}
}

Explicando la sintaxis —

Paso 1:
Declaración de una función async


async function process() { ... }
Nota: Toda función async devuelve automáticamente una promesa y nos permite usar await dentro de ella.
Paso 2: Crear un objeto con un async iterable


const asyncIterable = {
async *[Symbol.asyncIterator]() {
yield "uno";
yield "dos";
yield "tres";
},
};

Donde:

  • Al llamarse asyncIterable[Symbol.asyncIterator](), devuelve un AsyncGenerator (objeto asincrónicamente iterable).
  • Este generador produce (yield) valores uno a uno, como una secuencia.
  • Cada yield se envuelve automáticamente en una Promise.

Paso 3: Usar for await...of


for await (const val of asyncIterable) {
console.log(val);
}

Donde:

  • Itera de manera asincrónica sobre un objeto que implemente Symbol.asyncIterator.
  • Espera con await a que cada yield produzca un valor.
  • Asigna ese valor a val y ejecuta el cuerpo del bloque console.log(val).

Resumiendo:

  • for await llama a asyncIterator() y entra al generador.
  • Primer yield — "uno" se resuelve y se imprime.
  • Segundo yield — "dos" se resuelve y se imprime.
  • Tercer yield — "tres" se resuelve y se imprime.
  • Generador finaliza — done: true el bucle termina.

Ejemplo 1: Delays simulados


async function* delayedValues() {
const delays = [4000, 2000, 3000];
for (const ms of delays) {
await new Promise(res => setTimeout(res, ms));
yield ms;
}
}

async function logDelays() {
for await (const ms of delayedValues()) {
console.log(`Esperado: ${ms}ms`);
}
}

logDelays();

Donde:

delayedValues es un generador asincrónico (async function*) que:

  • Espera 4s, luego devuelve 4000.
  • Espera 2s, luego devuelve 2000.
  • Espera 3s, luego devuelve 3000.

logDelays usa for await...of para:

  • Iterar sobre cada valor generado por delayedValues.
  • Esperar que cada Promise se resuelva antes de continuar.
  • Imprimir: Esperado: 4000ms, Esperado: 2000ms, Esperado: 3000ms.


Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.



Útil para: simular tareas asincrónicas que se resuelven en tiempos diferentes (como llamadas a APIs que tardan distinto).
Ejemplo 2 — Paginación de películas populares con TMDb + for await...of


const API_KEY = 'TU API KEY';
const BASE_URL = '

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.



async function fetchMoviesPage(page) {
const url = `${BASE_URL}?language=en-US&page=${page}`;
const res = await fetch(url, {
headers: { Authorization: `Bearer ${API_KEY}`}
});

if (!res.ok) throw new Error(`Error HTTP ${res.status}`);
return res.json();
}

// Generador que devuelve todas las películas de TMDb
async function* fetchAllPopularMovies(maxPages = 3) {
let page = 1;
while (page <= maxPages) {
// Invocamos la función que devuelve las películas de la página actual
const data = await fetchMoviesPage(page);
// Recorremos los resultados de la página actual y devolvemos la película actual
for (const movie of data.results) {
yield movie;
}

if (page >= data.total_pages) break;
page++;
}
}

// Función principal que muestra las películas de TMDb
async function main() {
console.log('Películas populares de TMDb:');
for await (const movie of fetchAllPopularMovies()) {
console.log(`= ${movie.title} (${movie.release_date})`);
}
}

// Llamamos a la función principal
main().catch(console.error);

Donde:

  • fetchAllPopularMovies() es un async generator que va página por página.
  • Usa yield para entregar una película a la vez.
  • main() consume las películas una por una con for await...of.


Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.



Útil para: Procesamiento en batch, consolas, scripts backend, testing, pre-fetch de datos al montar componentes en Next.js.
Soporte —


A considerar —

  • Solo puede usarse dentro de funciones async.
  • Ideal para procesar streams, resultados paginados, o APIs con espera.
  • No mezclarlo con .map() o .forEach() si cada paso depende del anterior.
  • Prefiere for await...of cuando el orden importa y hay espera real.
03.Promise.prototype.finally


.finally() es un nuevo método en la cadena de Promesas que se ejecuta después de que la promesa se resuelve o rechaza, sin modificar el valor original.

Principales características —

  • Se ejecuta siempre, sin importar si fue .then o .catch.
  • No cambia el resultado de la promesa.
  • Ideal para limpiar recursos o resetear estados.

Ventajas —

  • Reemplaza patrones repetitivos como duplicar setLoading(false) en .then y .catch.
  • Mejora la claridad y estructura del código asincrónico.

Sintaxis —


fetch('/api/data')
.then(res => res.json())
.catch(err => console.error(err))
.finally(() => console.log('Petición finalizada'));
  • Se ejecuta después de .then() o .catch().
  • No recibe parámetros.
  • Retorna una promesa.
  • Si lanzas un error o devuelves una promesa rechazada dentro de .finally(), ese error reemplaza el flujo

Ejemplo 1 — Simulación de espera


function simulateRequest() {
return new Promise((resolve, reject) => {
const success = Math.random() > 0.5;
setTimeout(() => {
success ? resolve('Operación exitosa') : reject('Ocurrió un error');
}, 1000);
});
}

simulateRequest()
.then(console.log)
.catch(console.log)
.finally(() => {
console.log('entra a finally');
});


Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.



Ejemplo 2 — Ocultar un loader en React


'use client';

import { useState, useEffect } from 'react';

interface ProfileProps {
name: string;
email: string;
}

function ProfileLoader() {
const [loading, setLoading] = useState(false);
const [profile, setProfile] = useState<ProfileProps | null>(null);
const [error, setError] = useState(null);

useEffect(() => {
setLoading(true);
fetch('

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

')
.then((res) => {
if (!res.ok) throw new Error('Error al cargar');
return res.json();
})
.then(setProfile)
.catch((err) => setError(err.message))
.finally(() => setLoading(false));
}, []);

if (loading) return <p>Cargando...</p>;
if (error) return <p>Error: {error}</p>;

return profile ? (
<div>
<h1>{profile.name}</h1>
<p>{profile.email}</p>
</div>
) : null;
}

export default ProfileLoader;


Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.



Soporte —


A considerar —

  • No devuelvas nuevos valores dentro de .finally() ya que se se ignoran.
  • Usalo para tareas neutrales como limpiar loaders, cerrar conexiones, etc.
  • Evita lógica pesada en .finally().


Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

 
Вверх Снизу