Pregunta 1¿Qué pasa si ejecutas localStorage.getItem("theme") con una clave que nunca se guardó?
localStorage — guardar datos en el navegador
setItem, getItem y removeItem de localStorage para guardar valores en el navegador, arrays guardados como cadenas JSON, el null de las claves que faltan y el límite de espacio.
Si guardas en variables los productos del carrito o la configuración de visualización que eligió el usuario, se pierden al recargar o cerrar la página, y la próxima vez que se abra todo vuelve a su estado inicial. Hasta ahora no has visto ninguna forma de conservar valores después de volver a abrir la página.
En este artículo verás localStorage, que guarda valores en el navegador, y las cadenas JSON que se usan para guardar arrays y objetos.
Conservar valores al cerrar la página — setItem y getItem
Un sitio de noticias quiere recordar el tamaño de letra que eligió el usuario para usarlo la próxima vez que lo visite. Aunque lo guardes en una variable, como en const fontSize = "large";, las variables se pierden al recargar o cerrar la página, así que la siguiente carga no puede leerlo.
localStorage (un almacén de pares clave-valor que ofrece el navegador) guarda un valor con setItem(clave, valor), lo lee con getItem(clave) y lo elimina con removeItem(clave).
El almacenamiento está separado por origen (la parte de la URL antes de la ruta: https://news.example en https://news.example/settings), y las páginas del mismo origen leen y escriben los mismos valores.
// Si todavía hay un valor guardado de antes, lo quita para empezar sin nada guardado
localStorage.removeItem("fontSize");
// Guarda el valor cuando el usuario cambia el tamaño de letra a grande
localStorage.setItem("fontSize", "large");
// Al abrir la página, lee el valor guardado y lo usa
const fontSize = localStorage.getItem("fontSize");
console.log(fontSize); // large
// Guardar con la misma clave reemplaza el valor anterior
localStorage.setItem("fontSize", "small");
console.log(localStorage.getItem("fontSize")); // small
- Las páginas y pestañas de este origen comparten un localStorage
"fontSize"→"small"(reemplazado al guardar con la misma clave)- Se conserva al cerrar o recargar la página
- Variables como
const fontSize - Al recargar, las variables se vuelven a crear
- Tiene su propio localStorage
- No puede leer el
"fontSize"que guardó news.example
Si lees con getItem al abrir la página y escribes con setItem cuando el usuario cambia la configuración, la página muestra el mismo tamaño de letra incluso después de recargarla. Los valores guardados se conservan hasta que el código de la página los elimina o el usuario los borra desde la configuración del navegador.
Lo que guardas en los ejercicios se conserva para la siguiente ejecución
La consola de los ejercicios ejecuta todos los ejercicios de JavaScript del sitio en el mismo origen, así que todos comparten un único localStorage, y su contenido se conserva aunque vuelvas a abrir la página. Para que los valores guardados en ejecuciones anteriores no se mezclen con tus resultados, los ejercicios empiezan quitando con removeItem las claves que usan.
Guardar arrays y objetos — JSON.stringify
Un sitio de reservas de viaje guarda en un array los hoteles que el usuario agregó a favoritos y quiere volver a listarlos en su próxima visita. Pasar el array directamente a setItem no produce ningún error, pero en el valor que lees después no están ni los números de los hoteles ni sus nombres.
setItem convierte en cadena el valor que le pasas antes de guardarlo. Convierte los arrays y objetos en cadenas JSON con JSON.stringify antes de guardarlos, y convierte la cadena que lees de vuelta en el array u objeto original con JSON.parse.
// Si todavía hay un valor guardado de antes, lo quita primero
localStorage.removeItem("favoriteHotels");
const favoriteHotels = [{ id: "H-101", name: "Hotel Puerto" }, { id: "H-204", name: "Hostal Estación" }];
// Si lo pasas directamente, el array se convierte en cadena al guardarlo
localStorage.setItem("favoriteHotels", favoriteHotels);
console.log(localStorage.getItem("favoriteHotels")); // [object Object],[object Object]
// Conviértelo en una cadena JSON antes de guardarlo
localStorage.setItem("favoriteHotels", JSON.stringify(favoriteHotels));
const saved = localStorage.getItem("favoriteHotels");
console.log(saved); // [{"id":"H-101","name":"Hotel Puerto"},{"id":"H-204","name":"Hostal Estación"}]
// Convierte la cadena que leíste en un array antes de usarla
const restored = JSON.parse(saved);
console.log(restored[1].name); // Hostal Estación
Los números y los booleanos también se convierten en cadena sin ningún aviso ni error, así que solo te das cuenta cuando falla un cálculo o una comprobación con if sobre el valor que leíste. La tabla de abajo muestra, para cada valor que se pasa a setItem, la cadena que se guarda y qué pasa al leerla.
| Valor pasado a setItem | Cadena guardada | Al leerla |
|---|---|---|
| El número 20 | "20" | "20" + 1 da "201" (usa Number) |
| El booleano false | "false" | Es true en un if (usa JSON.parse) |
| Array de cadenas ["A-1", "B-2"] | "A-1,B-2" | Una cadena unida por comas |
Leer una clave que no está guardada — el null de getItem
En un sitio de recetas, los números de las recetas vistas se guardan como historial, y al abrir la página se muestra cuántas hay. Quien entra por primera vez o borró su historial no tiene nada guardado, así que, si lees el length del resultado de JSON.parse dando por hecho que hay historial, esa línea lanza un TypeError.
Si le pasas a getItem una clave que no está guardada, devuelve null, no undefined. Si escribes JSON.parse(localStorage.getItem(clave)) ?? [], se usa un array vacío solo cuando no hay nada guardado.
// Lee el historial de recetas vistas. Si no hay nada guardado, usa un array vacío
function loadHistory() {
return JSON.parse(localStorage.getItem("viewHistory")) ?? [];
}
// Primera visita: no hay nada guardado, así que getItem devuelve null
localStorage.removeItem("viewHistory");
console.log(localStorage.getItem("viewHistory")); // null
console.log(loadHistory().length); // 0
// Con un historial guardado: la cadena vuelve a ser un array
localStorage.setItem("viewHistory", JSON.stringify(["R-12", "R-30"]));
console.log(loadHistory().length); // 2
// Después de removeItem: vuelve a ser null
localStorage.removeItem("viewHistory");
console.log(loadHistory().length); // 0
Si pones el código de lectura en una función, quien la llama puede tratar el resultado como array sin comprobar si es null, incluso después de que se llame a removeItem al cerrar sesión. removeItem no lanza ningún error aunque la clave no esté guardada, así que no hace falta comprobar si hay algo guardado antes de quitarlo.
Recuperar el carrito después de recargar — funciones para guardar y cargar
Ahora, el carrito de una tienda en línea debe conservar su contenido cuando se recarga la página después de agregar un producto. Agregar un producto con cart.push solo cambia la variable, así que, si en algún lugar olvidas la línea que guarda, ese producto desaparece al recargar.
Pon el guardado en una función saveCart y la carga en una función loadCart, y llámalas justo después de cambiar el carrito y al abrir la página. setItem es síncrono (termina de guardar antes de pasar a la línea siguiente), así que, a diferencia de fetch, puedes leer el valor guardado en la línea siguiente sin await.
localStorage.removeItem("cart"); // Si todavía hay un carrito guardado de antes, lo quita
// Guarda el carrito como cadena JSON. No hace falta await
function saveCart(cart) {
localStorage.setItem("cart", JSON.stringify(cart));
}
// Convierte el carrito guardado en array. Si no hay nada guardado, devuelve un carrito vacío
function loadCart() {
return JSON.parse(localStorage.getItem("cart")) ?? [];
}
// Carga al abrir la página y guarda después de agregar un producto
const cart = loadCart();
cart.push({ id: "K-310", qty: 1 });
saveCart(cart);
// En lugar de recargar, vuelve a cargar desde la cadena guardada sin usar la variable cart
const reloaded = loadCart();
console.log(reloaded.length, reloaded[0].id); // 1 K-310
Si pones todo lo que cambia el carrito en una sola función y llamas a saveCart al final, no tienes que escribir el guardado en cada lugar donde la llamas, y no puedes olvidarlo. La carga también está dentro de loadCart, así que tampoco hay ningún lugar donde puedas olvidar ?? [].
setItem lanza una excepción cuando el almacenamiento está lleno
En Chrome, un origen puede guardar unos 5.24 millones de caracteres, sumando claves y valores. Si se supera ese límite, setItem lanza un QuotaExceededError y el valor no se guarda. Las lecturas y escrituras son síncronas, así que la página también deja de responder mientras se guarda un valor grande. Usa localStorage para valores pequeños, como carritos y configuraciones.
Verificación de conocimientos
Responde cada pregunta una a una.
Pregunta 2Después de localStorage.setItem("darkMode", false), ¿qué pasa si usas el valor leído como condición de un if?
Pregunta 3Si recargas después de cart.push(book) sin llamar a saveCart, ¿qué devuelve loadCart()?