Volver al blog

JavaScript en DAW: cómo aprobar Desarrollo Web en Entorno Cliente

JavaScript en DAW: cómo aprobar Desarrollo Web en Entorno Cliente

Llegas a segundo de DAW después de un año de Java. Tipos estrictos, un compilador que te avisa de casi todo y un main por el que empieza el programa. Y de repente te ponen delante JavaScript, donde "5" + 1 da "51", una variable puede ser un número y luego un texto, y el código no se ejecuta de arriba abajo cuando hay un fetch por medio.

Desarrollo Web en Entorno Cliente (DWEC) es el módulo de JavaScript del ciclo. Lo que más cuesta no es el lenguaje en sí. Es que tienes que entender a la vez cómo funciona JavaScript, cómo funciona el navegador y en qué momento ocurre cada cosa. Si te falla una de las tres, el error parece de las otras dos.

Qué entra en DWEC

El temario cambia un poco según la comunidad y el centro, pero casi siempre gira alrededor de estos bloques:

Bloque Qué haces Lo que más falla
Fundamentos del lenguaje Variables, tipos, funciones, arrays, objetos Conversiones de tipo, == frente a ===, var frente a let
DOM Leer y modificar la página desde JavaScript Elementos que todavía no existen cuando el script se ejecuta
Eventos Clics, teclado, envío de formularios Pasar la función mal al addEventListener
Formularios Validar datos antes de enviarlos La página se recarga y se pierde todo
Asincronía fetch, promesas, async/await, JSON Usar los datos antes de que lleguen
Almacenamiento localStorage, sessionStorage, cookies Guardar objetos sin convertirlos a texto
Framework (según centro) React, Vue, Angular o, en materiales antiguos, jQuery Saltar al framework sin dominar lo anterior

Las prácticas suelen ser una página que pide datos a una API, los pinta en una tabla o en tarjetas y deja filtrar, añadir o borrar. Si sabes hacer eso de principio a fin con JavaScript sin framework, tienes la mayor parte del módulo.

Los errores que vemos una y otra vez

Estos no salen de un listado genérico. Son los que más aparecen cuando un alumno de DAW comparte pantalla y nos dice "no sé por qué no funciona".

1. El script busca un elemento que todavía no existe

<head>
  <script src="app.js"></script>
</head>
<body>
  <button id="enviar">Enviar</button>
</body>
// app.js
const boton = document.querySelector("#enviar");
boton.addEventListener("click", enviar);
// TypeError: Cannot read properties of null (reading 'addEventListener')

El navegador lee el HTML de arriba abajo. Cuando llega al <script>, el botón aún no se ha creado, así que querySelector devuelve null. La solución más limpia es añadir defer:

<script src="app.js" defer></script>

Con defer el script se descarga en paralelo y se ejecuta cuando el HTML ya está entero. Cada vez que veas Cannot read properties of null, la primera pregunta es: ¿existe ese elemento en el momento en que lo busco? La segunda: ¿he escrito bien el selector? Un # que falta o un . donde iba # da exactamente el mismo error.

2. Llamar a la función en vez de pasarla

boton.addEventListener("click", enviar());  // mal
boton.addEventListener("click", enviar);    // bien

Con paréntesis, enviar() se ejecuta en ese mismo momento, al cargar la página, y lo que le pasas al addEventListener es lo que devuelve (normalmente undefined). El clic después no hace nada. Si necesitas pasarle argumentos, envuélvela:

boton.addEventListener("click", () => enviar(usuario));

3. El formulario recarga la página

Validas los campos, muestras el mensaje de error y desaparece en medio segundo. No es que tu código no funcione: el formulario se ha enviado y la página se ha recargado. Hay que cancelar el comportamiento por defecto:

formulario.addEventListener("submit", (evento) => {
  evento.preventDefault();
  // validar y, si todo está bien, enviar con fetch
});

Escucha el evento submit del formulario, no el click del botón. Así también se valida cuando el usuario pulsa Intro en un campo.

4. Lo que viene de un input siempre es texto

const minimo = document.querySelector("#minimo").value;  // "9"
const maximo = document.querySelector("#maximo").value;  // "10"
console.log(minimo + 1);       // "91"
console.log(minimo > maximo);  // true: compara como texto, letra a letra

value siempre devuelve un string, aunque el input sea type="number". La suma concatena, y la comparación entre dos textos va carácter a carácter: "9" es mayor que "1", así que "9" > "10". Si comparas con un número (minimo > 5), JavaScript sí convierte y funciona. Ese "a veces funciona y a veces no" es lo peor que puede pasar, porque no te das cuenta. Conviértelo nada más leerlo y comprueba que es un número:

const minimo = Number(document.querySelector("#minimo").value);
if (Number.isNaN(minimo)) {
  // mostrar error
}

Ojo con un caso que se cuela en muchas validaciones: Number("") da 0, no NaN. Si el campo puede quedar vacío, compruébalo antes con input.value.trim() === "".

Viniendo de Java, este es probablemente el cambio de mentalidad más grande: en JavaScript nadie te avisa de que estás mezclando tipos. Por eso conviene usar siempre ===, que no convierte nada antes de comparar.

5. Usar los datos de fetch antes de que lleguen

let productos = [];

fetch("/api/productos")
  .then((respuesta) => respuesta.json())
  .then((datos) => {
    productos = datos;
  });

console.log(productos.length); // 0

El console.log se ejecuta antes de que la respuesta llegue. fetch no detiene el programa: lanza la petición y sigue. Todo lo que dependa de los datos tiene que ir después de que lleguen, y con async/await se lee mucho mejor:

async function cargarProductos() {
  const respuesta = await fetch("/api/productos");
  if (!respuesta.ok) {
    throw new Error(`Error ${respuesta.status}`);
  }
  return respuesta.json();
}

async function iniciar() {
  try {
    const productos = await cargarProductos();
    pintarProductos(productos);
  } catch (error) {
    mostrarError("No se han podido cargar los productos");
  }
}

iniciar();

Fíjate en el if (!respuesta.ok). Mucha gente cree que fetch falla si el servidor devuelve un 404 o un 500, y no es así. fetch solo se rechaza si no hay conexión o la petición no puede salir. Un 404 es una respuesta válida, así que si no lo compruebas tú, acabarás intentando pintar un mensaje de error como si fuera tu lista de productos.

6. querySelectorAll no devuelve un array

const precios = document.querySelectorAll(".precio");
precios.map((p) => Number(p.textContent)); // TypeError: precios.map is not a function

Devuelve una NodeList. Tiene forEach, pero no map, filter ni reduce. Si necesitas esos métodos, conviértela antes:

const total = [...document.querySelectorAll(".precio")]
  .map((p) => Number(p.textContent))
  .reduce((suma, precio) => suma + precio, 0);

7. Guardar un objeto en localStorage tal cual

localStorage.setItem("carrito", carrito);
localStorage.getItem("carrito"); // "[object Object]"

localStorage solo guarda texto. Para objetos y arrays hay que pasar por JSON en los dos sentidos:

localStorage.setItem("carrito", JSON.stringify(carrito));
const guardado = JSON.parse(localStorage.getItem("carrito")) ?? [];

El ?? [] cubre la primera vez, cuando todavía no hay nada guardado y getItem devuelve null.

La pregunta del orden de ejecución

En muchos exámenes de DWEC cae alguna variante de esta:

console.log("A");
setTimeout(() => console.log("B"), 0);
Promise.resolve().then(() => console.log("C"));
console.log("D");

La respuesta es A, D, C, B. Primero se ejecuta todo el código síncrono (A y D). Después, las promesas resueltas (C). Y por último, los temporizadores (B), aunque tengan 0 milisegundos. No hace falta que te sepas de memoria el nombre de cada cola, pero sí esta regla: síncrono, después promesas, después temporizadores y eventos.

Y otra clásica, la del bucle con var:

for (var i = 0; i < 3; i++) {
  setTimeout(() => console.log(i), 100);
}
// 3, 3, 3

Con var solo hay una variable i para todo el bucle, y cuando los setTimeout se ejecutan ya vale 3. Con let cada vuelta tiene su propia i y sale 0, 1, 2. Es una de las razones por las que hoy se usa let y const, y casi nunca var.

Cómo prepararlo

Haz el mismo proyecto pequeño tres veces. Una página que pide datos a una API pública, los pinta, permite filtrarlos y guarda favoritos en localStorage. La primera vez con ayuda, la segunda mirando solo cuando te atasques y la tercera sin mirar nada. Es casi todo el temario en un ejercicio.

Vive con la consola del navegador abierta. Pulsa F12. La pestaña Consola te dice el error y la línea exacta. La pestaña Red (Network) te enseña si la petición de fetch ha salido, qué código ha devuelto y qué datos ha traído. La mitad de los "no me funciona el fetch" se resuelven mirando ahí. El método general lo tienes en cómo depurar código paso a paso.

Antes de pintar, haz console.log de los datos. Muchas veces el fallo es que la API devuelve { results: [...] } y tú estás recorriendo el objeto como si fuera el array.

No empieces por el framework. Si tu centro da React o Angular, llegará. Pero un componente de React que no funciona porque no entiendes map, las promesas o la desestructuración es muy difícil de arreglar. Primero JavaScript sin nada; luego el framework se aprende mucho más rápido.

Practica para el formato del examen. Si es en ordenador sin internet, entrena sin autocompletado ni IA. Si es en papel, escribe a mano funciones con eventos y fetch. En cómo preparar un examen práctico de programación hay un plan para las últimas semanas.

Cuándo pedir ayuda

Si haces las prácticas y cuando algo falla acabas encontrando el porqué, vas bien. Merece la pena buscar a alguien cuando:

  • Tu código funciona a veces y no sabes por qué deja de hacerlo.
  • Copias ejemplos de fetch o de promesas, funcionan, pero no podrías escribirlos tú solo.
  • Te han dado un framework en clase y te sientes perdido desde el primer día.
  • Tienes el examen o la entrega del proyecto en pocas semanas y estás bloqueado.

En nuestras clases particulares de JavaScript trabajamos sobre tu práctica y con el temario de tu centro: abrimos tu código, buscamos el punto exacto donde se rompe y lo arreglas tú, para que la próxima vez no dependas de nadie. Si te pesa más de un módulo de segundo, lo vemos todo junto en las clases para DAM y DAW. Son online, uno a uno, a 25 € la hora y sin matrícula ni permanencia.

Preguntas frecuentes

¿Qué es DWEC en DAW?

Son las siglas de Desarrollo Web en Entorno Cliente, el módulo de segundo de DAW en el que se aprende JavaScript para el navegador: manipular la página, responder a eventos, validar formularios y comunicarse con un servidor mediante fetch. Su pareja es Desarrollo Web en Entorno Servidor (DWES), donde se programa la parte del servidor, a menudo con PHP.

¿Es difícil JavaScript si vengo de Java?

La sintaxis te va a resultar muy familiar, y eso es justo la trampa. Los if, los bucles y las funciones se parecen, pero los tipos dinámicos, la asincronía y la forma de trabajar con el DOM no tienen equivalente en lo que hiciste en primero. Lo que más cuesta es dejar de suponer que el código se ejecuta línea a línea cuando hay peticiones o eventos de por medio.

¿Hay que saber HTML y CSS para DWEC?

Sí, al menos lo básico. Vas a buscar elementos por su id o su clase, crear etiquetas y cambiar estilos desde JavaScript, así que necesitas entender la estructura de una página. Lo de primero de Lenguajes de marcas suele ser suficiente.

¿Se puede aprobar DWEC usando ChatGPT para las prácticas?

Puedes entregar prácticas así, pero el examen lo haces solo y muchas prácticas se defienden delante del profesor. Úsalo para que te explique un error o te ponga ejercicios parecidos, no para que te escriba el código que entregas. Si en primero ya tuviste problemas con Programación, repasa cómo aprobar Programación en DAM o DAW: el método sirve igual para JavaScript.

¿Qué framework se da en DAW?

Depende del centro y del profesor. Lo más habitual hoy es React, Angular o Vue, y en materiales más antiguos todavía aparece jQuery. A veces el framework se da en DWEC y otras en Diseño de Interfaces Web. Sea cual sea, todos se apoyan en lo mismo: funciones, arrays, objetos, eventos y promesas.

WhatsApp