La clase `JSON` en JavaScript
Este artículo explica la clase JSON en JavaScript.
Explicaremos la clase JSON en JavaScript con ejemplos prácticos.
YouTube Video
La clase JSON en JavaScript
El objeto JSON tiene principalmente dos métodos. JSON.stringify() convierte un objeto en una cadena JSON y JSON.parse() crea un objeto a partir de una cadena JSON. JSON es un formato de intercambio de datos que solo puede expresar algunos valores de JavaScript. Las funciones, undefined, Symbol y las referencias circulares no pueden convertirse directamente en JSON.
JSON.stringify()
Primero, aquí hay un ejemplo básico de cómo convertir un objeto en una cadena JSON.
1// Convert a JavaScript object to a JSON string.
2const obj = { name: "Alice", age: 30, active: true };
3const jsonString = JSON.stringify(obj);
4console.log(jsonString); // {"name":"Alice","age":30,"active":true}
- Este código es el ejemplo más básico de convertir un objeto común en una cadena JSON.
JSON.stringifydevuelve la cadena de forma sincrónica.
El segundo argumento de JSON.stringify (replacer)
Al especificar replacer, el segundo argumento de JSON.stringify, puedes controlar detalladamente las reglas de conversión. Aquí tienes un ejemplo usando un array para conservar solo propiedades específicas.
1// Use a replacer array to include only specific properties during stringification.
2const user = { id: 1, name: "Bob", password: "secret", role: "admin" };
3const safeJson = JSON.stringify(user, ["id", "name", "role"]);
4console.log(safeJson); // {"id":1,"name":"Bob","role":"admin"}
- En este ejemplo,
passwordse excluye para permitir un registro seguro. Esto es útil cuando quieres eliminar información sensible por razones de seguridad.
Usando replacer como función (para conversión y filtrado de valores)
Si quieres más flexibilidad, puedes proporcionar una función para procesar cada clave y valor. A continuación, un ejemplo de cómo mantener una Date como cadena ISO.
1// Use a replacer function to customize serialization.
2const data = { name: "Carol", joined: new Date("2020-01-01T12:00:00Z") };
3const jsonCustom = JSON.stringify(data, (key, value) => {
4 // Convert Date objects to ISO strings explicitly
5 if (this && this[key] instanceof Date) {
6 return this[key].toISOString();
7 }
8 return value;
9});
10console.log(jsonCustom); // {"name":"Carol","joined":"2020-01-01T12:00:00.000Z"}
- En un
replacerde tipo función, se pasan la clave y el valor y el valor devuelto se utiliza en el JSON final.thishace referencia al objeto padre, por lo que también puede utilizarse para conversiones anidadas.
Fundamentos de JSON.parse()
JSON.parse convierte una cadena JSON de vuelta en un objeto. Envuélvelo con try/catch para poder manejar JSON inválido.
1// Parse a JSON string into an object and handle parsing errors.
2const jsonText = '{"title":"Example","count":42}';
3try {
4 const parsed = JSON.parse(jsonText);
5 console.log(parsed.title); // Example
6} catch (err) {
7 console.error("Invalid JSON:", err.message);
8}- Si la cadena es inválida, se lanzará una excepción, así que siempre incluye manejo de excepciones al tratar con fuentes externas.
Restauración personalizada usando reviver (ejemplo de restaurar un objeto Date)
Usando el segundo argumento reviver de JSON.parse, puedes realizar la restauración de valores. Aquí tienes un ejemplo de cómo convertir una fecha almacenada como cadena de vuelta a un objeto Date.
1// Use a reviver to turn ISO date strings back into Date objects.
2const jsonWithDate = '{"name":"Dana","joined":"2021-06-15T09:00:00.000Z"}';
3const obj = JSON.parse(jsonWithDate, (key, value) => {
4 // A simple check for ISO date-like strings
5 if (typeof value === "string" && /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z$/.test(value)) {
6 return new Date(value);
7 }
8 return value;
9});
10console.log(obj.joined instanceof Date); // true
reviverse llama para cada clave y el valor devuelto se utiliza en el objeto final. Por favor, realiza una verificación estricta del formato de fecha según tu aplicación.
Pretty-print y el argumento space
Para imprimir con sangría y mejorar la legibilidad, pasa un número o cadena como tercer argumento a JSON.stringify.
1// Pretty-print an object with 2-space indentation for readability.
2const config = { host: "localhost", port: 3000, debug: true };
3const pretty = JSON.stringify(config, null, 2);
4console.log(pretty);
5/* {
6 "host": "localhost",
7 "port": 3000,
8 "debug": true
9} */- Para JSON destinado a ser leído por personas, como logs o archivos de configuración, es útil especificar una sangría. Sin embargo, ten en cuenta que esto aumenta el tamaño.
Cómo manejar referencias circulares
JSON.stringify lanza un TypeError si hay una referencia circular. Una solución común es crear un replacer usando un conjunto seen para evitar referencias circulares.
1// Safely stringify objects that may contain circular references.
2function safeStringify(value) {
3 const seen = new WeakSet();
4 return JSON.stringify(value, (key, val) => {
5 if (val && typeof val === "object") {
6 if (seen.has(val)) return "[Circular]";
7 seen.add(val);
8 }
9 return val;
10 });
11}
12
13const a = { name: "A" };
14a.self = a;
15console.log(safeStringify(a)); // {"name":"A","self":"[Circular]"}
- Al usar un
WeakSet, puedes detectar referencias circulares y evitar fugas de memoria. En el caso de una referencia circular, devuelve"[Circular]". También es posible asignar un ID de referencia en lugar de"[Circular]".
Serialización personalizada con el método toJSON
Si defines un método toJSON en un objeto, JSON.stringify utiliza su valor de retorno. Esto es útil cuando quieres establecer reglas de conversión para cada tipo.
1// Define toJSON on a class to customize its JSON representation.
2class Point {
3 constructor(x, y) {
4 this.x = x;
5 this.y = y;
6 }
7 toJSON() {
8 // This will be used by JSON.stringify
9 return { x: this.x, y: this.y, type: "Point" };
10 }
11}
12
13const p = new Point(10, 20);
14console.log(JSON.stringify(p)); // {"x":10,"y":20,"type":"Point"}
toJSONte permite definir reglas de serialización a nivel de objeto, lo que resulta más localizado e intuitivo que usarreplacer.
Limitaciones y advertencias de JSON
Ejemplos notables que no pueden ser convertidos a JSON son undefined, funciones, Symbol, BigInt y referencias circulares. También ten en cuenta la precisión numérica (por ejemplo, enteros grandes y el redondeo de coma flotante IEEE).
1// Demonstrate values that can't be represented in JSON.
2const sample = {
3 a: undefined,
4 b: function () {},
5 c: Symbol("s"),
6 d: 9007199254740993n // BigInt (note: JSON.stringify will throw on BigInt)
7};
8// JSON.stringify will throw for BigInt and will drop undefined, functions, symbols in objects.
9try {
10 console.log(JSON.stringify(sample));
11} catch (err) {
12 console.error("Error during stringify:", err.message);
13}- Al manejar
BigInt, conviértelo en una cadena o define su representación usando unreplacerpersonalizado otoJSON.
Seguridad (al manejar JSON no confiable)
JSON.parse en sí es seguro y se considera más seguro que eval, pero confiar ciegamente en el objeto parseado y usarlo directamente para acceder a propiedades o realizar consultas a la base de datos es peligroso. Siempre valida y verifica que los datos se ajusten al esquema esperado.
1// Parse external JSON and validate expected properties before use.
2const external = '{"username":"eve","role":"user"}';
3const parsed = JSON.parse(external);
4if (typeof parsed.username === "string" && ["user","admin"].includes(parsed.role)) {
5 console.log("Safe to use parsed.username and parsed.role.");
6} else {
7 throw new Error("Invalid payload");
8}- Para la validación de entrada (validación de esquema), usar librerías como
ajves robusto.
Consideraciones de rendimiento
Serializar y deserializar objetos grandes de forma frecuente carga la CPU y la memoria. Si es necesario, puedes considerar enviar solo las diferencias, usar formatos binarios (como MessagePack) o trabajar en modo streaming (procesar datos secuencialmente). En entornos de navegador, en algunos casos puedes usar structuredClone (para copiar) u objetos transferibles en postMessage.
Recomendaciones específicas (breve)
También puedes considerar los siguientes puntos:.
- Para logs, evita el pretty-print y usa JSON en una sola línea para reducir el tamaño.
- Los objetos que se serializan con frecuencia deben optimizarse previamente, por ejemplo, eliminando propiedades innecesarias.
- Usa
replacerpara minimizar el recorrido y excluir propiedades innecesarias.
Ejemplo práctico: flujo de envío/recepción de solicitudes API
Finalmente, aquí tienes una secuencia que muestra cómo convertir de manera segura un objeto a JSON para enviarlo a un servidor y restaurar una fecha desde la respuesta recibida.
1// Prepare payload, stringify safely, send via fetch, and revive dates on response.
2async function sendUserUpdate(url, user) {
3 // Remove sensitive info before sending
4 const payload = JSON.stringify(user, (k, v) => (k === "password" ? undefined : v));
5 const res = await fetch(url, {
6 method: "POST",
7 headers: { "Content-Type": "application/json" },
8 body: payload
9 });
10
11 const text = await res.text();
12 // Reviver: convert ISO date strings back to Date
13 const data = JSON.parse(text, (key, value) => {
14 if (typeof value === "string" && /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z$/.test(value)) {
15 return new Date(value);
16 }
17 return value;
18 });
19 return data;
20}- En este ejemplo,
passwordse excluye antes de enviar y la fecha se restaura medianterevivertras recibir. En la operación real, deberás agregar manejo de errores y gestión de timeouts.
Resumen
Usando JSON.stringify() y JSON.parse(), puedes convertir entre objetos y cadenas. Puedes personalizar el proceso de conversión usando replacer y reviver, y si implementas toJSON en una clase, también puedes controlar cada objeto de forma individual. Las referencias circulares, BigInt, funciones, etc. no pueden manejarse tal cual, por lo que debes procesarlas previamente.
Siempre valida la entrada externa y asegúrate de que la información sensible no se incluya en logs o comunicaciones. Si el tamaño de los datos es grande, es eficiente evitar el pretty-print, considerar la transmisión diferencial o usar formatos binarios.
Puedes seguir el artículo anterior utilizando Visual Studio Code en nuestro canal de YouTube. Por favor, también revisa nuestro canal de YouTube.