Proyecto final JavaScript: aplicación de tareas con DOM, eventos y localStorage

Proyecto final de JavaScript: construí una aplicación de tareas con DOM, eventos, arrays, objetos, filtros y localStorage.

En este proyecto vamos a integrar los conceptos principales de la ruta de JavaScript construyendo una aplicación de tareas.

La aplicación permitirá agregar, completar, eliminar y filtrar tareas. Además guardará los datos en localStorage para conservarlos al recargar la página.

Qué vamos a practicar

  • variables y constantes;
  • funciones;
  • arrays y objetos;
  • métodos de array;
  • DOM;
  • eventos;
  • formularios;
  • delegación de eventos;
  • JSON;
  • localStorage.

Estructura del proyecto

tareas-js/
|-- index.html
|-- styles.css
|-- app.js

HTML

<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Mis tareas</title>
    <link rel="stylesheet" href="styles.css">
    <script src="app.js" defer></script>
</head>
<body>

    <main class="app">

        <h1>Mis tareas</h1>

        <form id="form-tarea">
            <label for="titulo">Nueva tarea</label>
            <input
                id="titulo"
                name="titulo"
                type="text"
                maxlength="80"
                required
            >
            <button type="submit">Agregar</button>
        </form>

        <div class="filtros">
            <button data-filtro="todas">Todas</button>
            <button data-filtro="pendientes">Pendientes</button>
            <button data-filtro="completadas">Completadas</button>
        </div>

        <p id="resumen"></p>

        <ul id="lista-tareas"></ul>

    </main>

</body>
</html>

CSS mínimo

body {
    font-family: Arial, sans-serif;
    margin: 0;
    background: #f4f6f8;
}

.app {
    width: 90%;
    max-width: 700px;
    margin: 3rem auto;
}

form,
.filtros {
    display: flex;
    gap: 0.75rem;
    margin-bottom: 1rem;
    flex-wrap: wrap;
}

li {
    display: flex;
    justify-content: space-between;
    gap: 1rem;
    padding: 1rem;
    margin-bottom: 0.75rem;
    background: white;
    border-radius: 8px;
}

.completada {
    text-decoration: line-through;
    opacity: 0.6;
}

Estado inicial

Primero guardamos referencias a los elementos del DOM y definimos el estado de la aplicación: el array de tareas y el filtro activo.

const formulario = document.querySelector("#form-tarea");
const inputTitulo = document.querySelector("#titulo");
const lista = document.querySelector("#lista-tareas");
const resumen = document.querySelector("#resumen");
const filtros = document.querySelector(".filtros");

let tareas = cargarTareas();
let filtroActual = "todas";

Cargar desde localStorage

Al iniciar la aplicación intentamos recuperar las tareas guardadas. Si no existen o el contenido no es válido, comenzamos con un array vacío.

function cargarTareas() {
    const guardadas = localStorage.getItem("tareas");

    if (!guardadas) {
        return [];
    }

    try {
        return JSON.parse(guardadas);
    } catch (error) {
        console.error("Datos inválidos en localStorage", error);
        return [];
    }
}

Guardar tareas

Cada vez que cambia el array de tareas lo convertimos a JSON y lo guardamos. De esta manera los datos sobreviven a una recarga de la página.

function guardarTareas() {
    localStorage.setItem("tareas", JSON.stringify(tareas));
}

localStorage guarda strings. Por eso convertimos el array a JSON antes de almacenarlo y lo reconstruimos con JSON.parse().

Crear una tarea

Centralizamos la creación en una función para que todas las tareas tengan siempre la misma estructura: identificador, título y estado de completada.

function crearTarea(titulo) {
    return {
        id: Date.now(),
        titulo,
        completada: false
    };
}

Filtrar tareas

La función no modifica el array original: usa filter() para devolver únicamente las tareas que corresponden al filtro seleccionado.

function obtenerTareasVisibles() {
    if (filtroActual === "pendientes") {
        return tareas.filter(tarea => !tarea.completada);
    }

    if (filtroActual === "completadas") {
        return tareas.filter(tarea => tarea.completada);
    }

    return tareas;
}

Renderizar

Renderizar significa tomar el estado actual y reflejarlo en la interfaz. Primero limpiamos la lista y después volvemos a crear los elementos visibles.

function renderizar() {
    lista.innerHTML = "";

    const visibles = obtenerTareasVisibles();

    visibles.forEach(tarea => {
        const item = document.createElement("li");

        if (tarea.completada) {
            item.classList.add("completada");
        }

        item.dataset.id = tarea.id;

        const texto = document.createElement("span");
        texto.textContent = tarea.titulo;

        const acciones = document.createElement("div");

        const botonCompletar = document.createElement("button");
        botonCompletar.type = "button";
        botonCompletar.dataset.accion = "completar";
        botonCompletar.textContent = tarea.completada
            ? "Desmarcar"
            : "Completar";

        const botonEliminar = document.createElement("button");
        botonEliminar.type = "button";
        botonEliminar.dataset.accion = "eliminar";
        botonEliminar.textContent = "Eliminar";

        acciones.append(botonCompletar, botonEliminar);
        item.append(texto, acciones);
        lista.append(item);
    });

    const pendientes = tareas.filter(
        tarea => !tarea.completada
    ).length;

    resumen.textContent =
        `${pendientes} tarea(s) pendiente(s)`;
}

Agregar desde el formulario

Interceptamos el envío, validamos el texto, agregamos una nueva tarea al array, guardamos y volvemos a renderizar.

formulario.addEventListener("submit", event => {
    event.preventDefault();

    const titulo = inputTitulo.value.trim();

    if (titulo === "") {
        return;
    }

    tareas.push(crearTarea(titulo));

    guardarTareas();
    renderizar();

    formulario.reset();
    inputTitulo.focus();
});

Completar y eliminar con delegación

En lugar de crear un evento para cada botón, escuchamos un solo click en la lista. Según el atributo data-accion decidimos qué operación ejecutar.

lista.addEventListener("click", event => {
    const boton = event.target.closest("button");

    if (!boton) {
        return;
    }

    const item = boton.closest("li");
    const id = Number(item.dataset.id);
    const accion = boton.dataset.accion;

    if (accion === "completar") {
        tareas = tareas.map(tarea => {
            if (tarea.id === id) {
                return {
                    ...tarea,
                    completada: !tarea.completada
                };
            }

            return tarea;
        });
    }

    if (accion === "eliminar") {
        tareas = tareas.filter(tarea => tarea.id !== id);
    }

    guardarTareas();
    renderizar();
});

Cambiar filtros

Los botones sólo cambian filtroActual. Después llamamos nuevamente a renderizar() para que la interfaz refleje ese nuevo estado.

filtros.addEventListener("click", event => {
    const boton = event.target.closest("[data-filtro]");

    if (!boton) {
        return;
    }

    filtroActual = boton.dataset.filtro;

    renderizar();
});

Inicializar

La primera llamada a renderizar() muestra inmediatamente las tareas recuperadas de localStorage.

renderizar();

app.js completo

const formulario = document.querySelector("#form-tarea");
const inputTitulo = document.querySelector("#titulo");
const lista = document.querySelector("#lista-tareas");
const resumen = document.querySelector("#resumen");
const filtros = document.querySelector(".filtros");

let tareas = cargarTareas();
let filtroActual = "todas";

function cargarTareas() {
    const guardadas = localStorage.getItem("tareas");

    if (!guardadas) {
        return [];
    }

    try {
        return JSON.parse(guardadas);
    } catch (error) {
        console.error("Datos inválidos en localStorage", error);
        return [];
    }
}

function guardarTareas() {
    localStorage.setItem("tareas", JSON.stringify(tareas));
}

function crearTarea(titulo) {
    return {
        id: Date.now(),
        titulo,
        completada: false
    };
}

function obtenerTareasVisibles() {
    if (filtroActual === "pendientes") {
        return tareas.filter(tarea => !tarea.completada);
    }

    if (filtroActual === "completadas") {
        return tareas.filter(tarea => tarea.completada);
    }

    return tareas;
}

function renderizar() {
    lista.innerHTML = "";

    const visibles = obtenerTareasVisibles();

    visibles.forEach(tarea => {
        const item = document.createElement("li");

        if (tarea.completada) {
            item.classList.add("completada");
        }

        item.dataset.id = tarea.id;

        const texto = document.createElement("span");
        texto.textContent = tarea.titulo;

        const acciones = document.createElement("div");

        const completar = document.createElement("button");
        completar.type = "button";
        completar.dataset.accion = "completar";
        completar.textContent = tarea.completada
            ? "Desmarcar"
            : "Completar";

        const eliminar = document.createElement("button");
        eliminar.type = "button";
        eliminar.dataset.accion = "eliminar";
        eliminar.textContent = "Eliminar";

        acciones.append(completar, eliminar);
        item.append(texto, acciones);
        lista.append(item);
    });

    const pendientes = tareas.filter(
        tarea => !tarea.completada
    ).length;

    resumen.textContent =
        `${pendientes} tarea(s) pendiente(s)`;
}

formulario.addEventListener("submit", event => {
    event.preventDefault();

    const titulo = inputTitulo.value.trim();

    if (titulo === "") {
        return;
    }

    tareas.push(crearTarea(titulo));

    guardarTareas();
    renderizar();

    formulario.reset();
    inputTitulo.focus();
});

lista.addEventListener("click", event => {
    const boton = event.target.closest("button");

    if (!boton) {
        return;
    }

    const item = boton.closest("li");
    const id = Number(item.dataset.id);

    if (boton.dataset.accion === "completar") {
        tareas = tareas.map(tarea =>
            tarea.id === id
                ? { ...tarea, completada: !tarea.completada }
                : tarea
        );
    }

    if (boton.dataset.accion === "eliminar") {
        tareas = tareas.filter(tarea => tarea.id !== id);
    }

    guardarTareas();
    renderizar();
});

filtros.addEventListener("click", event => {
    const boton = event.target.closest("[data-filtro]");

    if (!boton) {
        return;
    }

    filtroActual = boton.dataset.filtro;

    renderizar();
});

renderizar();

Qué aprendimos con el proyecto

  • mantener un estado en un array;
  • modelar cada tarea con un objeto;
  • renderizar el estado en el DOM;
  • procesar formularios;
  • usar delegación de eventos;
  • transformar arrays con map y filter;
  • guardar y recuperar JSON con localStorage.

Mejoras para seguir practicando

  • editar tareas;
  • agregar prioridades;
  • incorporar fechas límite;
  • ordenar pendientes y completadas;
  • agregar contador por filtro;
  • confirmar antes de eliminar;
  • reemplazar localStorage por una API.

Después de esta ruta

Con estos fundamentos ya podés profundizar en módulos, clases, tooling, testing, frameworks y desarrollo frontend moderno. Lo importante es que DOM, eventos, arrays, objetos, asincronía y HTTP estén claros antes de depender de una librería.


¿Te sirvió esta guía? ☕

Si este contenido te ayudó a aprender JavaScript, podés apoyar a Club Programador. Cada aporte ayuda a mantener el sitio online y a seguir publicando material gratuito.

🇦🇷 Apoyar desde Argentina

☕ Invitame un café con Mercado Pago

🌎 Apoyar desde otro país

☕ Apoyar con PayPal

Seguí aprendiendo JavaScript

← JavaScript asíncrono: Promises, async/await, fetch y APIs

Con este proyecto completás la ruta inicial de JavaScript.

JavaScript asíncrono: Promises, async/await, fetch y APIs

Aprendé JavaScript asíncrono con Promises, async/await, fetch, manejo de errores y consumo de APIs.

Muchas tareas no terminan inmediatamente: una petición HTTP, un temporizador o una lectura externa pueden requerir esperar.

setTimeout

setTimeout() programa una función para ejecutarse después de un tiempo. No detiene el resto del programa mientras espera.

console.log("Inicio");

setTimeout(() => {
    console.log("Pasaron dos segundos");
}, 2000);

console.log("Fin");

El programa no bloquea toda la ejecución esperando el temporizador.

Qué es una Promise

Una Promise representa el resultado futuro de una operación. Puede estar pendiente, resolverse correctamente o rechazarse por un error.

Una Promise representa un resultado que puede estar pendiente, completarse correctamente o fallar.

pending
fulfilled
rejected

Ejemplo de Promise

const promesa = new Promise((resolve, reject) => {
    const correcto = true;

    if (correcto) {
        resolve("Operación completada");
    } else {
        reject(new Error("Ocurrió un error"));
    }
});

promesa
    .then(resultado => console.log(resultado))
    .catch(error => console.error(error));

async y await

async marca una función como asíncrona y await permite esperar una Promise con una sintaxis más parecida al código secuencial.

async function obtenerDatos() {
    const resultado = await Promise.resolve("Datos recibidos");

    console.log(resultado);
}

obtenerDatos();

await solo puede utilizarse dentro de una función async o en contextos de módulos que permitan top-level await.

fetch

fetch() realiza una petición HTTP y devuelve una Promise. Después debemos leer el cuerpo de la respuesta, por ejemplo con response.json().

fetch() permite realizar peticiones HTTP desde el navegador.

async function cargarUsuarios() {
    const respuesta = await fetch("https://jsonplaceholder.typicode.com/users");

    const usuarios = await respuesta.json();

    console.log(usuarios);
}

cargarUsuarios();

Comprobar el estado HTTP

fetch() no rechaza automáticamente una Promise por respuestas como 404 o 500. Por eso comprobamos response.ok o el código de estado.

async function cargarUsuarios() {
    const respuesta = await fetch("https://jsonplaceholder.typicode.com/users");

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

    return respuesta.json();
}

try…catch

try...catch permite manejar errores sin interrumpir abruptamente la aplicación. Dentro de catch podemos informar el problema o mostrar una alternativa al usuario.

async function iniciar() {
    try {
        const usuarios = await cargarUsuarios();
        console.log(usuarios);
    } catch (error) {
        console.error("No se pudieron cargar los usuarios", error);
    }
}

iniciar();

Mostrar datos en el DOM

<ul id="usuarios"></ul>
async function mostrarUsuarios() {
    const lista = document.querySelector("#usuarios");

    try {
        const respuesta = await fetch(
            "https://jsonplaceholder.typicode.com/users"
        );

        if (!respuesta.ok) {
            throw new Error("Error HTTP");
        }

        const usuarios = await respuesta.json();

        usuarios.forEach(usuario => {
            const item = document.createElement("li");
            item.textContent = usuario.name;
            lista.append(item);
        });
    } catch (error) {
        lista.textContent = "No se pudieron cargar los datos";
    }
}

mostrarUsuarios();

GET y POST: dos métodos HTTP fundamentales

GET y POST son métodos del protocolo HTTP. No son funciones propias de JavaScript: indican qué tipo de operación queremos realizar sobre un recurso de una API.

GET: obtener información

Usamos GET principalmente para consultar datos. Una petición GET normalmente no debería modificar información en el servidor.

Con fetch(), GET es el método por defecto, por eso no hace falta indicarlo explícitamente:

const respuesta = await fetch("/api/tareas");

const tareas = await respuesta.json();

console.log(tareas);

También podemos enviar parámetros en la URL. Por ejemplo, para pedir únicamente tareas completadas:

const respuesta = await fetch(
    "/api/tareas?completada=true"
);

Esos datos viajan en la URL y suelen utilizarse para filtros, búsquedas, paginación u otras opciones de consulta.

POST: enviar información

Usamos POST normalmente para crear o enviar datos al servidor. A diferencia de GET, los datos suelen viajar en el cuerpo de la petición.

const respuesta = await fetch("/api/tareas", {
    method: "POST",
    headers: {
        "Content-Type": "application/json"
    },
    body: JSON.stringify({
        titulo: "Practicar JavaScript"
    })
});

const tareaCreada = await respuesta.json();

console.log(tareaCreada);

En este ejemplo:

  • method: "POST" indica que queremos enviar información;
  • Content-Type: application/json informa al servidor que el cuerpo contiene JSON;
  • JSON.stringify() convierte el objeto de JavaScript a texto JSON;
  • response.json() convierte la respuesta JSON del servidor nuevamente en un valor JavaScript.

GET o POST: ¿cuál usar?

GET  → consultar información
POST → enviar o crear información

Por ejemplo, listar tareas sería normalmente un GET, mientras que crear una nueva tarea sería un POST.

Una API no siempre es pública

Algunas APIs necesitan autenticación, claves, permisos o restricciones CORS. No debemos exponer secretos privados dentro del JavaScript que se ejecuta en el navegador.

Promise.all

Promise.all() espera varias Promises en paralelo y devuelve sus resultados juntos. Es útil cuando las operaciones no dependen unas de otras.

const [usuarios, publicaciones] = await Promise.all([
    fetch("/api/usuarios").then(r => r.json()),
    fetch("/api/publicaciones").then(r => r.json())
]);

Ejercicio

Consumí una API pública de prueba, mostrale al usuario un mensaje de “Cargando…”, renderizá los resultados y manejá un posible error.

Errores comunes

  • olvidar await;
  • suponer que fetch rechaza automáticamente cualquier HTTP 404 o 500;
  • no usar try...catch;
  • exponer claves privadas en el frontend;
  • intentar consumir una API bloqueada por CORS sin entender el origen del problema.

¿Te sirvió esta guía? ☕

Si este contenido te ayudó a aprender JavaScript, podés apoyar a Club Programador. Cada aporte ayuda a mantener el sitio online y a seguir publicando material gratuito.

🇦🇷 Apoyar desde Argentina

☕ Invitame un café con Mercado Pago

🌎 Apoyar desde otro país

☕ Apoyar con PayPal

Seguí aprendiendo JavaScript

← Eventos y formularios en JavaScript: click, input, submit y validaciones

Proyecto final JavaScript: aplicación de tareas con DOM, eventos y localStorage →

Eventos y formularios en JavaScript: click, input, submit y validaciones

Aprendé eventos y formularios en JavaScript: click, input, change, submit, preventDefault, FormData y validaciones.

Los eventos permiten que JavaScript responda a acciones del usuario o cambios que ocurren en la página.

addEventListener

addEventListener() conecta una función con un evento. Cuando ese evento ocurre, JavaScript ejecuta la función que registramos.

<button id="boton">Hacer clic</button>
const boton = document.querySelector("#boton");

boton.addEventListener("click", () => {
    console.log("El usuario hizo clic");
});

Objeto event

El objeto event contiene información sobre lo ocurrido, por ejemplo qué elemento originó el evento mediante event.target.

boton.addEventListener("click", event => {
    console.log(event.target);
});

Evento input

input se dispara cada vez que cambia el valor de un campo mientras el usuario escribe o interactúa con él.

<input id="nombre" type="text">
<p id="salida"></p>
const input = document.querySelector("#nombre");
const salida = document.querySelector("#salida");

input.addEventListener("input", event => {
    salida.textContent = event.target.value;
});

Evento change

change suele utilizarse cuando queremos reaccionar al cambio confirmado de un control, como un select o un checkbox.

change suele utilizarse cuando nos interesa reaccionar al cambio confirmado de un control, por ejemplo un select.

submit

El evento submit pertenece al formulario, no al botón. Escucharlo en el formulario permite capturar envíos realizados tanto con clic como con la tecla Enter.

<form id="formulario">
    <label for="email">Correo</label>
    <input id="email" name="email" type="email">
    <button type="submit">Enviar</button>
</form>
const formulario = document.querySelector("#formulario");

formulario.addEventListener("submit", event => {
    event.preventDefault();

    console.log("Formulario interceptado");
});

preventDefault()

preventDefault() evita la acción automática del navegador asociada al evento. En formularios nos permite validar o procesar los datos antes de decidir qué hacer.

Evita el comportamiento por defecto del navegador. En un formulario, por ejemplo, impide el envío tradicional mientras procesamos los datos con JavaScript.

Leer valores

const email = document.querySelector("#email");

formulario.addEventListener("submit", event => {
    event.preventDefault();

    console.log(email.value);
});

FormData

FormData reúne los campos de un formulario usando sus atributos name. Así podemos leer sus valores sin seleccionar cada input por separado.

formulario.addEventListener("submit", event => {
    event.preventDefault();

    const datos = new FormData(formulario);

    console.log(datos.get("email"));
});

Validación simple

formulario.addEventListener("submit", event => {
    event.preventDefault();

    const email = document.querySelector("#email").value.trim();

    if (email === "") {
        console.log("El correo es obligatorio");
        return;
    }

    console.log("Formulario válido");
});

HTML y JavaScript se complementan

HTML ya ofrece atributos como required, minlength o type="email". JavaScript puede agregar reglas de negocio y mensajes más específicos.

Delegación de eventos

La delegación consiste en escuchar el evento en un elemento padre y detectar qué hijo lo originó. Es especialmente útil cuando los elementos se crean dinámicamente.

<ul id="tareas">
    <li data-id="1">Estudiar</li>
    <li data-id="2">Practicar</li>
</ul>
const tareas = document.querySelector("#tareas");

tareas.addEventListener("click", event => {
    if (event.target.matches("li")) {
        console.log(event.target.dataset.id);
    }
});

La delegación resulta muy útil para listas dinámicas.

Ejercicio

Creá un formulario con nombre y edad. Validá que el nombre tenga al menos 3 caracteres y que la edad sea mayor que 0. Mostrá mensajes en el DOM sin recargar la página.

Errores comunes

  • olvidar preventDefault();
  • registrar el listener sobre el elemento equivocado;
  • leer valores sin aplicar trim() cuando corresponde;
  • depender solo de validación del cliente para seguridad;
  • crear listeners repetidos innecesariamente.

¿Te sirvió esta guía? ☕

Si este contenido te ayudó a aprender JavaScript, podés apoyar a Club Programador. Cada aporte ayuda a mantener el sitio online y a seguir publicando material gratuito.

🇦🇷 Apoyar desde Argentina

☕ Invitame un café con Mercado Pago

🌎 Apoyar desde otro país

☕ Apoyar con PayPal

Seguí aprendiendo JavaScript

← DOM en JavaScript: seleccionar, modificar y crear elementos HTML

JavaScript asíncrono: Promises, async/await, fetch y APIs →

DOM en JavaScript: seleccionar, modificar y crear elementos HTML

Aprendé a trabajar con el DOM en JavaScript: querySelector, textContent, classList, atributos, crear y eliminar elementos.

El DOM es la representación en memoria que el navegador construye a partir del documento HTML.

JavaScript puede utilizar esa representación para leer y modificar la página.

HTML de ejemplo

<main>
    <h1 id="titulo">Club Programador</h1>
    <p class="descripcion">Aprendé JavaScript.</p>
    <ul id="lista"></ul>
</main>

querySelector

querySelector() devuelve el primer elemento que coincide con un selector CSS. Si no encuentra ninguno, devuelve null.

const titulo = document.querySelector("#titulo");

console.log(titulo);

querySelectorAll

querySelectorAll() devuelve todos los elementos coincidentes en una colección que podemos recorrer con forEach().

const parrafos = document.querySelectorAll("p");

parrafos.forEach(parrafo => {
    console.log(parrafo.textContent);
});

textContent

textContent permite leer o reemplazar el texto de un elemento sin interpretar HTML.

const titulo = document.querySelector("#titulo");

titulo.textContent = "Aprender JavaScript";

innerHTML

innerHTML permite leer o reemplazar el contenido HTML interno de un elemento. Es más potente que textContent, pero debemos evitar insertar contenido no confiable.

const contenedor = document.querySelector("#lista");

contenedor.innerHTML = "<li>HTML</li><li>CSS</li>";

innerHTML es útil en algunos escenarios, pero no conviene insertar allí contenido no confiable porque puede introducir problemas de seguridad.

classList

classList permite agregar, quitar o alternar clases CSS sin reemplazar todas las clases existentes del elemento.

const titulo = document.querySelector("#titulo");

titulo.classList.add("destacado");
titulo.classList.remove("oculto");
titulo.classList.toggle("activo");

Atributos

Con setAttribute() y getAttribute() podemos modificar o consultar atributos HTML como href, src o title.

const enlace = document.querySelector("a");

enlace.setAttribute("href", "https://clubprogramador.com/");
console.log(enlace.getAttribute("href"));

Crear elementos

document.createElement() crea un nodo nuevo en memoria. Para que aparezca en la página debemos insertarlo después con métodos como append().

const lista = document.querySelector("#lista");

const item = document.createElement("li");

item.textContent = "JavaScript";

lista.append(item);

Crear varios elementos desde datos

const tecnologias = ["HTML", "CSS", "JavaScript"];
const lista = document.querySelector("#lista");

tecnologias.forEach(tecnologia => {
    const item = document.createElement("li");
    item.textContent = tecnologia;
    lista.append(item);
});

Eliminar elementos

remove() elimina directamente un elemento del DOM.

const elemento = document.querySelector(".mensaje");

elemento.remove();

dataset

dataset permite leer atributos personalizados data-*. Son muy útiles para asociar identificadores u otra información simple a elementos HTML.

<button data-id="25">Eliminar</button>
const boton = document.querySelector("button");

console.log(boton.dataset.id);

Renderizar una lista

const cursos = [
    { id: 1, nombre: "HTML" },
    { id: 2, nombre: "CSS" },
    { id: 3, nombre: "JavaScript" }
];

const lista = document.querySelector("#lista");

function renderizarCursos() {
    lista.innerHTML = "";

    cursos.forEach(curso => {
        const item = document.createElement("li");
        item.textContent = curso.nombre;
        lista.append(item);
    });
}

renderizarCursos();

Separar datos y presentación

Una práctica importante es mantener los datos en arrays u objetos y crear funciones específicas para reflejarlos en el DOM.

Ejercicio

Creá un array de cinco tecnologías y renderizalo como lista. Agregá una clase especial a JavaScript y un botón que vacíe la lista.

Errores comunes

  • buscar un selector que no existe;
  • confundir querySelector con querySelectorAll;
  • usar innerHTML indiscriminadamente;
  • duplicar elementos por no limpiar antes de renderizar;
  • mezclar toda la lógica de datos con manipulación del DOM.

¿Te sirvió esta guía? ☕

Si este contenido te ayudó a aprender JavaScript, podés apoyar a Club Programador. Cada aporte ayuda a mantener el sitio online y a seguir publicando material gratuito.

🇦🇷 Apoyar desde Argentina

☕ Invitame un café con Mercado Pago

🌎 Apoyar desde otro país

☕ Apoyar con PayPal

Seguí aprendiendo JavaScript

← Objetos y JSON en JavaScript: propiedades, métodos y destructuring

Eventos y formularios en JavaScript: click, input, submit y validaciones →

Objetos y JSON en JavaScript: propiedades, métodos y destructuring

Aprendé objetos y JSON en JavaScript: propiedades, métodos, destructuring, spread, arrays de objetos y JSON.parse/stringify.

Los objetos permiten agrupar datos relacionados mediante pares de propiedad y valor.

Crear un objeto

const persona = {
    nombre: "Ana",
    edad: 28,
    activo: true
};

Acceder a propiedades

Podemos acceder a una propiedad con notación de punto o con corchetes. Los corchetes son útiles cuando el nombre de la propiedad está guardado en una variable.

console.log(persona.nombre);
console.log(persona["edad"]);

Modificar y agregar propiedades

Los objetos pueden cambiar después de crearse: podemos actualizar propiedades existentes o agregar nuevas.

persona.edad = 29;
persona.ciudad = "Santa Rosa";

Métodos

Cuando una propiedad contiene una función, solemos llamarla método. En el ejemplo, saludar() pertenece al objeto usuario.

const usuario = {
    nombre: "Luis",

    saludar() {
        return `Hola, soy ${this.nombre}`;
    }
};

console.log(usuario.saludar());

Objetos anidados

Una propiedad también puede contener otro objeto. Esto permite representar información más compleja manteniendo los datos agrupados.

const alumno = {
    nombre: "María",
    contacto: {
        email: "maria@example.com",
        telefono: "123456"
    }
};

console.log(alumno.contacto.email);

Arrays de objetos

const cursos = [
    { id: 1, nombre: "HTML", activo: true },
    { id: 2, nombre: "CSS", activo: true },
    { id: 3, nombre: "JavaScript", activo: false }
];

const activos = cursos.filter(curso => curso.activo);

Destructuring de objetos

El destructuring permite extraer propiedades y guardarlas directamente en variables, evitando repetir el nombre del objeto.

const producto = {
    nombre: "Monitor",
    precio: 250000
};

const { nombre, precio } = producto;

console.log(nombre, precio);

Renombrar al desestructurar

const { nombre: nombreProducto } = producto;

console.log(nombreProducto);

Spread en objetos

El operador spread ... copia las propiedades de un objeto en otro. Es muy útil para crear una nueva versión con algunos valores modificados.

const original = {
    nombre: "Ana",
    edad: 30
};

const actualizado = {
    ...original,
    edad: 31
};

console.log(actualizado);

¿Qué es JSON?

JSON significa JavaScript Object Notation. Es un formato de texto utilizado para intercambiar datos entre sistemas.

{
    "nombre": "Ana",
    "edad": 30,
    "activo": true
}

Aunque se parece a la sintaxis de objetos de JavaScript, JSON es un formato de texto con reglas propias.

JSON.stringify()

JSON.stringify() convierte un objeto JavaScript en texto JSON. Esto es útil para enviarlo por una API o guardarlo en almacenamiento local.

const usuario = {
    nombre: "Ana",
    edad: 30
};

const texto = JSON.stringify(usuario);

console.log(texto);

JSON.parse()

JSON.parse() hace el proceso inverso: recibe texto JSON válido y lo convierte en un valor JavaScript utilizable.

const texto = '{"nombre":"Ana","edad":30}';

const usuario = JSON.parse(texto);

console.log(usuario.nombre);

Optional chaining

El operador ?. permite acceder de forma segura a propiedades que podrían no existir, evitando que ese acceso lance un error.

const usuario = {
    nombre: "Ana"
};

console.log(usuario.contacto?.email);

Si una parte de la cadena no existe, devuelve undefined en lugar de generar un error en ese acceso.

Ejercicio

Creá un array de productos con id, nombre, precio y stock. Buscá uno por id, actualizá su stock usando spread y convertí el resultado a JSON.

Errores comunes

  • confundir objeto JavaScript con JSON;
  • intentar usar métodos dentro de JSON;
  • acceder a propiedades anidadas que no existen;
  • modificar objetos compartidos sin querer;
  • usar JSON.parse() sobre texto que no es JSON válido.

¿Te sirvió esta guía? ☕

Si este contenido te ayudó a aprender JavaScript, podés apoyar a Club Programador. Cada aporte ayuda a mantener el sitio online y a seguir publicando material gratuito.

🇦🇷 Apoyar desde Argentina

☕ Invitame un café con Mercado Pago

🌎 Apoyar desde otro país

☕ Apoyar con PayPal

Seguí aprendiendo JavaScript

← Arrays en JavaScript: métodos, recorridos, map, filter, find y reduce

DOM en JavaScript: seleccionar, modificar y crear elementos HTML →

Arrays en JavaScript: métodos, recorridos, map, filter, find y reduce

Aprendé arrays en JavaScript: creación, índices, push, pop, includes, find, filter, map, reduce y recorridos.

Los arrays permiten almacenar múltiples valores dentro de una misma estructura.

Crear un array

const lenguajes = ["JavaScript", "Python", "PHP"];

Índices

En JavaScript los arrays comienzan en índice 0.

const lenguajes = ["JavaScript", "Python", "PHP"];

console.log(lenguajes[0]);
console.log(lenguajes[2]);

length

length indica cuántos elementos contiene el array. No es una función: es una propiedad.

console.log(lenguajes.length);

Agregar y quitar elementos

push() agrega al final, unshift() al principio, pop() elimina el último y shift() elimina el primero. Estos métodos modifican el array original.

const tareas = ["Estudiar"];

tareas.push("Practicar");
tareas.unshift("Leer");

tareas.pop();
tareas.shift();

includes

includes() responde con true o false según exista o no un valor dentro del array.

const tecnologias = ["HTML", "CSS", "JavaScript"];

console.log(tecnologias.includes("CSS"));

indexOf

indexOf() devuelve la posición de un valor. Si no lo encuentra, devuelve -1.

console.log(tecnologias.indexOf("JavaScript"));

forEach

forEach() ejecuta una función una vez por cada elemento. Es útil para recorrer y realizar acciones, pero no crea un nuevo array.

const nombres = ["Ana", "Luis", "María"];

nombres.forEach(nombre => {
    console.log(nombre);
});

map

map() recorre todos los elementos y devuelve un nuevo array con el resultado de aplicar una transformación a cada uno. Mantiene la misma cantidad de elementos.

const precios = [100, 200, 300];

const preciosConIVA = precios.map(precio => precio * 1.21);

console.log(preciosConIVA);

filter

filter() crea un nuevo array únicamente con los elementos que cumplen una condición. No modifica el array original.

const notas = [4, 8, 6, 10, 3];

const aprobadas = notas.filter(nota => nota >= 6);

console.log(aprobadas);

find

find() devuelve el primer elemento que cumple una condición. Si no encuentra ninguno, devuelve undefined.

const usuarios = [
    { id: 1, nombre: "Ana" },
    { id: 2, nombre: "Luis" }
];

const usuario = usuarios.find(item => item.id === 2);

console.log(usuario);

some y every

some() devuelve true si al menos un elemento cumple la condición. every() sólo devuelve true si todos la cumplen.

const notas = [8, 7, 9];

console.log(notas.some(nota => nota === 10));
console.log(notas.every(nota => nota >= 6));

reduce

reduce() combina todos los elementos hasta obtener un único resultado, por ejemplo una suma, un total o una estructura acumulada.

const importes = [1000, 2500, 800];

const total = importes.reduce((acumulador, importe) => {
    return acumulador + importe;
}, 0);

console.log(total);

sort

sort() ordena el array y modifica el original. Para números debemos indicar cómo comparar dos valores, porque por defecto los trata como texto.

Para números conviene proporcionar una función de comparación.

const numeros = [10, 2, 30, 5];

numeros.sort((a, b) => a - b);

console.log(numeros);

Spread

El operador spread ... expande los elementos de un array. Es muy útil para crear copias superficiales o combinar arrays sin escribir ciclos manuales.

const originales = [1, 2, 3];
const copia = [...originales];

const todos = [...originales, 4, 5];

Destructuring

El destructuring permite extraer valores del array y guardarlos en variables según su posición.

const tecnologias = ["HTML", "CSS", "JavaScript"];

const [html, css, javascript] = tecnologias;

console.log(javascript);

Ejemplo completo

const productos = [
    { nombre: "Teclado", precio: 25000, stock: 4 },
    { nombre: "Mouse", precio: 18000, stock: 0 },
    { nombre: "Monitor", precio: 230000, stock: 2 }
];

const disponibles = productos.filter(producto => producto.stock > 0);

const nombres = disponibles.map(producto => producto.nombre);

const total = disponibles.reduce((suma, producto) => {
    return suma + producto.precio;
}, 0);

console.log(nombres);
console.log(total);

Ejercicio

Creá un array de alumnos con nombre y nota. Obtené aprobados, buscá un alumno, generá un array solo con nombres y calculá el promedio general.

Errores comunes

  • olvidar que el primer índice es 0;
  • modificar el array original sin querer;
  • usar map cuando realmente queremos filtrar;
  • usar find esperando varios resultados;
  • ordenar números sin función comparadora.

¿Te sirvió esta guía? ☕

Si este contenido te ayudó a aprender JavaScript, podés apoyar a Club Programador. Cada aporte ayuda a mantener el sitio online y a seguir publicando material gratuito.

🇦🇷 Apoyar desde Argentina

☕ Invitame un café con Mercado Pago

🌎 Apoyar desde otro país

☕ Apoyar con PayPal

Seguí aprendiendo JavaScript

← Funciones en JavaScript: parámetros, return, scope y arrow functions

Objetos y JSON en JavaScript: propiedades, métodos y destructuring →

Funciones en JavaScript: parámetros, return, scope y arrow functions

Aprendé funciones en JavaScript: parámetros, return, scope, funciones declaradas, expresiones y arrow functions.

Las funciones permiten agrupar lógica reutilizable y dividir un programa en piezas más pequeñas.

Declarar una función

function saludar() {
    console.log("Hola");
}

saludar();

Parámetros y argumentos

Los parámetros son los nombres que declaramos en la función. Los argumentos son los valores concretos que enviamos al llamarla.

function saludar(nombre) {
    console.log(`Hola, ${nombre}`);
}

saludar("Ana");
saludar("Luis");

return

return permite que una función entregue un resultado al código que la llamó. Esto es distinto de mostrar un valor con console.log().

function sumar(a, b) {
    return a + b;
}

const resultado = sumar(5, 8);

console.log(resultado);

return devuelve un valor y finaliza la ejecución de esa llamada a la función.

Más de un parámetro

function calcularPromedio(nota1, nota2, nota3) {
    return (nota1 + nota2 + nota3) / 3;
}

console.log(calcularPromedio(8, 7, 9));

Valores por defecto

function saludar(nombre = "Visitante") {
    return `Hola, ${nombre}`;
}

console.log(saludar());

Scope

El scope define desde qué parte del programa puede accederse a una variable. Las variables declaradas dentro de una función normalmente quedan limitadas a esa función.

El scope indica dónde puede utilizarse una variable.

const sitio = "Club Programador";

function ejemplo() {
    const mensaje = "Variable local";

    console.log(sitio);
    console.log(mensaje);
}

ejemplo();

// console.log(mensaje); // No está disponible aquí

Scope de bloque

if (true) {
    const activo = true;
    let puntos = 10;

    console.log(activo, puntos);
}

// activo y puntos no existen fuera del bloque

Function expression

Una function expression guarda una función dentro de una variable o constante. Esto permite tratar las funciones como valores y pasarlas a otras funciones.

const multiplicar = function (a, b) {
    return a * b;
};

console.log(multiplicar(4, 5));

Arrow functions

Las arrow functions ofrecen una sintaxis más corta y aparecen mucho en callbacks y métodos de arrays. No se comportan exactamente igual que una función tradicional respecto de this.

const multiplicar = (a, b) => {
    return a * b;
};

Si solo devolvemos una expresión:

const duplicar = numero => numero * 2;

console.log(duplicar(8));

¿Arrow function o function?

Las arrow functions son muy útiles, especialmente como callbacks. Sin embargo, no son un reemplazo idéntico para todas las funciones porque su comportamiento con this es diferente.

Funciones como valores

function ejecutar(accion) {
    accion();
}

ejecutar(() => {
    console.log("Función recibida como argumento");
});

Funciones puras como idea de diseño

function aplicarDescuento(precio, porcentaje) {
    return precio - precio * porcentaje / 100;
}

Esta función recibe datos y devuelve un resultado sin depender de variables externas ni modificar estado fuera de ella.

Ejercicio

Creá funciones para calcular subtotal, descuento e importe final de una compra.

Errores comunes

  • confundir imprimir con devolver un valor;
  • olvidar return;
  • depender demasiado de variables globales;
  • crear funciones enormes;
  • usar arrow functions sin entender sus diferencias.

¿Te sirvió esta guía? ☕

Si este contenido te ayudó a aprender JavaScript, podés apoyar a Club Programador. Cada aporte ayuda a mantener el sitio online y a seguir publicando material gratuito.

🇦🇷 Apoyar desde Argentina

☕ Invitame un café con Mercado Pago

🌎 Apoyar desde otro país

☕ Apoyar con PayPal

Seguí aprendiendo JavaScript

← Ciclos en JavaScript: for, while, for…of, break y continue

Arrays en JavaScript: métodos, recorridos, map, filter, find y reduce →

Ciclos en JavaScript: for, while, for…of, break y continue

Aprendé bucles en JavaScript con for, while, do while, for…of, break y continue mediante ejercicios prácticos.

Los ciclos permiten repetir instrucciones sin copiar el mismo código muchas veces.

for

Usamos for cuando conocemos o podemos controlar claramente cuántas repeticiones queremos realizar. Reúne inicialización, condición y actualización en una sola estructura.

for (let i = 1; i <= 5; i++) {
    console.log(i);
}

Cómo leer un for

inicio → condición → código → actualización → condición...

Tabla de multiplicar

const numero = 7;

for (let i = 1; i <= 10; i++) {
    console.log(`${numero} x ${i} = ${numero * i}`);
}

while

while repite un bloque mientras una condición sea verdadera. Es útil cuando no sabemos de antemano cuántas veces necesitaremos repetir.

let contador = 1;

while (contador <= 5) {
    console.log(contador);
    contador++;
}

do…while

En do...while la condición se evalúa al final, por eso el bloque se ejecuta al menos una vez.

let opcion = 1;

do {
    console.log("La opción es", opcion);
    opcion++;
} while (opcion <= 3);

La diferencia es que el bloque se ejecuta al menos una vez.

Recorrer un array con for

const nombres = ["Ana", "Luis", "María"];

for (let i = 0; i < nombres.length; i++) {
    console.log(nombres[i]);
}

for…of

for...of recorre directamente los valores de un array u otra estructura iterable. Es más simple que trabajar con índices cuando sólo necesitamos cada elemento.

const nombres = ["Ana", "Luis", "María"];

for (const nombre of nombres) {
    console.log(nombre);
}

for...of resulta muy cómodo para recorrer valores de estructuras iterables como arrays.

break

break corta el ciclo inmediatamente. Conviene usarlo cuando ya encontramos el resultado buscado y seguir recorriendo sería innecesario.

for (let i = 1; i <= 10; i++) {
    if (i === 6) {
        break;
    }

    console.log(i);
}

continue

continue salta solamente la iteración actual y continúa con la siguiente.

for (let i = 1; i <= 5; i++) {
    if (i === 3) {
        continue;
    }

    console.log(i);
}

Acumuladores

const numeros = [4, 7, 2, 9];
let suma = 0;

for (const numero of numeros) {
    suma += numero;
}

console.log(suma);

Buscar un valor

const numeros = [3, 8, 12, 5];
const buscado = 12;
let encontrado = false;

for (const numero of numeros) {
    if (numero === buscado) {
        encontrado = true;
        break;
    }
}

console.log(encontrado);

Bucles infinitos

Un ciclo se vuelve infinito si su condición nunca deja de ser verdadera.

let i = 1;

while (i <= 5) {
    console.log(i);
    i++;
}

Ejercicio

Recorré un array de notas, calculá el promedio y contá cuántas están aprobadas.

Errores comunes

  • olvidar actualizar el contador;
  • usar una condición incorrecta;
  • confundir índice con valor;
  • usar un ciclo cuando ya existe un método de array más expresivo;
  • crear bucles infinitos.

¿Te sirvió esta guía? ☕

Si este contenido te ayudó a aprender JavaScript, podés apoyar a Club Programador. Cada aporte ayuda a mantener el sitio online y a seguir publicando material gratuito.

🇦🇷 Apoyar desde Argentina

☕ Invitame un café con Mercado Pago

🌎 Apoyar desde otro país

☕ Apoyar con PayPal

Seguí aprendiendo JavaScript

← Condicionales en JavaScript: if, else, switch y operadores lógicos

Funciones en JavaScript: parámetros, return, scope y arrow functions →

Condicionales en JavaScript: if, else, switch y operadores lógicos

Aprendé a tomar decisiones en JavaScript con if, else, else if, switch, operadores lógicos y ternario.

Los condicionales permiten que un programa tome decisiones según los datos disponibles.

if

const edad = 20;

if (edad >= 18) {
    console.log("Puede ingresar");
}

if y else

const edad = 16;

if (edad >= 18) {
    console.log("Mayor de edad");
} else {
    console.log("Menor de edad");
}

else if

const nota = 8;

if (nota >= 9) {
    console.log("Excelente");
} else if (nota >= 6) {
    console.log("Aprobado");
} else {
    console.log("Desaprobado");
}

Operadores lógicos

const edad = 25;
const registrado = true;

if (edad >= 18 && registrado) {
    console.log("Acceso permitido");
}
const esAdmin = false;
const esEditor = true;

if (esAdmin || esEditor) {
    console.log("Puede editar");
}

Negación

const bloqueado = false;

if (!bloqueado) {
    console.log("Usuario habilitado");
}

Truthy y falsy

Cuando JavaScript espera una condición, convierte ciertos valores a verdadero o falso. Entender esto evita comparaciones innecesarias y ayuda a detectar valores vacíos o ausentes.

En contextos booleanos, algunos valores se consideran falsos, por ejemplo false, 0, "", null, undefined y NaN.

const nombre = "";

if (nombre) {
    console.log("Hay un nombre");
} else {
    console.log("Nombre vacío");
}

switch

switch resulta útil cuando una misma variable puede tomar varios valores concretos. Cada case representa una opción y default cubre los casos no contemplados.

const dia = 2;

switch (dia) {
    case 1:
        console.log("Lunes");
        break;
    case 2:
        console.log("Martes");
        break;
    default:
        console.log("Otro día");
}

Operador ternario

El operador ternario permite resolver una decisión simple en una sola expresión: condición ? valorSiVerdadero : valorSiFalso.

const edad = 21;

const mensaje = edad >= 18
    ? "Mayor de edad"
    : "Menor de edad";

console.log(mensaje);

Es útil para decisiones simples. Si la lógica crece, un if suele resultar más legible.

Validación de acceso

const usuario = "ana";
const claveCorrecta = true;
const activo = true;

if (usuario && claveCorrecta && activo) {
    console.log("Bienvenida");
} else {
    console.log("No se pudo iniciar sesión");
}

Ejercicio

Creá un programa que reciba una nota de 1 a 10 y muestre si el alumno está desaprobado, aprobado, muy bien o excelente.

Errores comunes

  • usar = cuando queríamos comparar;
  • olvidar break en un switch;
  • anidar demasiados if;
  • usar ternarios para lógica compleja;
  • no considerar valores vacíos o inválidos.

¿Te sirvió esta guía? ☕

Si este contenido te ayudó a aprender JavaScript, podés apoyar a Club Programador. Cada aporte ayuda a mantener el sitio online y a seguir publicando material gratuito.

🇦🇷 Apoyar desde Argentina

☕ Invitame un café con Mercado Pago

🌎 Apoyar desde otro país

☕ Apoyar con PayPal

Seguí aprendiendo JavaScript

← Variables, constantes, tipos de datos y operadores en JavaScript

Ciclos en JavaScript: for, while, for…of, break y continue →

Variables, constantes, tipos de datos y operadores en JavaScript

Aprendé let, const, tipos de datos, conversiones y operadores en JavaScript con ejemplos prácticos.

Para que un programa pueda trabajar con información necesita guardar valores, compararlos y transformarlos. En JavaScript utilizamos variables y constantes para hacerlo.

let y const

let edad = 25;
const nombre = "Ana";

let permite reasignar el valor. const impide reasignar la referencia.

let puntos = 10;
puntos = 15;

const pais = "Argentina";
// pais = "Uruguay"; // Error

¿Qué pasó con var?

var existe por compatibilidad histórica, pero en código moderno normalmente preferimos let y const por sus reglas de alcance más predecibles.

Tipos de datos primitivos

El tipo de dato indica qué clase de valor estamos manejando y qué operaciones tienen sentido sobre él. Por ejemplo, no tratamos igual un número que un texto o un valor verdadero/falso.

  • string;
  • number;
  • boolean;
  • undefined;
  • null;
  • bigint;
  • symbol.

Strings

const nombre = "Lucía";
const mensaje = 'Hola';
const saludo = `Hola, ${nombre}`;

Numbers

const edad = 30;
const precio = 1250.50;
const resultado = 10 / 3;

JavaScript utiliza el tipo number tanto para enteros como para números con decimales.

Boolean

const activo = true;
const terminado = false;

null y undefined

let respuesta;
const usuario = null;

console.log(respuesta); // undefined
console.log(usuario);   // null

undefined suele indicar ausencia de asignación. null se utiliza habitualmente para expresar ausencia de valor de forma intencional.

typeof

El operador typeof permite consultar el tipo de un valor. Es útil para depurar y para validar datos antes de procesarlos.

console.log(typeof "Hola");
console.log(typeof 25);
console.log(typeof true);

Conversión de tipos

A veces recibimos datos como texto —por ejemplo desde un formulario— aunque necesitemos operar con ellos como números. En esos casos hacemos una conversión explícita con funciones como Number() o String().

const texto = "25";

const numero = Number(texto);

console.log(numero + 5); // 30
const edad = 32;
const textoEdad = String(edad);

Operadores aritméticos

const a = 10;
const b = 3;

console.log(a + b);
console.log(a - b);
console.log(a * b);
console.log(a / b);
console.log(a % b);
console.log(a ** b);

Operadores de comparación

console.log(10 > 5);
console.log(10 < 5);
console.log(10 >= 10);
console.log(10 === 10);
console.log(10 !== 5);

=== frente a ==

En código moderno conviene preferir === y !==, porque comparan sin realizar conversiones implícitas inesperadas.

console.log(5 == "5");  // true
console.log(5 === "5"); // false

Operadores lógicos

const edad = 22;
const tieneEntrada = true;

const puedeIngresar = edad >= 18 && tieneEntrada;

console.log(puedeIngresar);
&&  → AND
||  → OR
!   → NOT

Template literals

Los template literals usan comillas invertidas y permiten insertar expresiones con ${...}. Son más cómodos que concatenar muchos textos con +.

const nombre = "Martín";
const puntos = 120;

console.log(`${nombre} tiene ${puntos} puntos`);

NaN

const valor = Number("hola");

console.log(valor);
console.log(Number.isNaN(valor));

Ejercicio

Pedí nombre, edad y año actual. Calculá aproximadamente el año de nacimiento y mostrale al usuario un mensaje usando template literals.

Errores comunes

  • usar var por costumbre;
  • intentar reasignar una constante;
  • sumar strings cuando se esperaban números;
  • usar == sin entender coerción;
  • confundir null con undefined.

¿Te sirvió esta guía? ☕

Si este contenido te ayudó a aprender JavaScript, podés apoyar a Club Programador. Cada aporte ayuda a mantener el sitio online y a seguir publicando material gratuito.

🇦🇷 Apoyar desde Argentina

☕ Invitame un café con Mercado Pago

🌎 Apoyar desde otro país

☕ Apoyar con PayPal

Seguí aprendiendo JavaScript

← Introducción a JavaScript: qué es, cómo funciona y cómo agregarlo a HTML

Condicionales en JavaScript: if, else, switch y operadores lógicos →