Pregunta 1En el constructor de una clase que tiene status = "Pendiente";, ¿qué obtienes al leer this.status?
El constructor y los campos de clase — cómo fijar los valores iniciales
Cómo fijan el constructor y los campos de clase los valores iniciales de una instancia: guardar argumentos, el orden de los campos, valores por defecto y rechazo de valores inválidos.
Un ticket de soporte tiene valores que cambian de un ticket a otro, como el título, y valores iniciales que son iguales en todos, como el estado «Pendiente». Si escribes la clase sin cuidado, los valores omitidos o inválidos terminan guardados en la instancia.
En este artículo verás el constructor, que recibe los valores que se pasan al crear la instancia, y los campos de clase, que declaran valores iniciales fijos.
Limpiar los argumentos antes de guardarlos — el cuerpo del constructor
Los títulos que llegan desde el formulario de soporte a veces traen espacios de más al principio o al final. Si armas un texto para mostrar como «Ana: No puedo iniciar sesión» después de crear la instancia, cada pantalla que lo muestre necesita su propio trim y su propio código para armar la cadena.
En el cuerpo del constructor no tienes que guardar el argumento sin cambios. Puedes guardar un valor ya limpio, como en this.title = title.trim(), o un valor formado a partir de varios argumentos. Así, cada pantalla solo lee las propiedades de la instancia y obtiene valores que ya están limpios.
class Ticket {
constructor(title, customerName) {
// Limpia el argumento antes de guardarlo en this
this.title = title.trim();
this.customerName = customerName;
// Arma el valor para mostrar a partir de this, después de la limpieza
this.label = `${this.customerName}: ${this.title}`;
// Si escribieras `${customerName}: ${title}`, quedarían los espacios del título
}
}
// Pasa un título con espacios antes y después
const ticket = new Ticket(" No puedo iniciar sesión ", "Ana");
console.log(ticket.title); // No puedo iniciar sesión
console.log(ticket.label); // Ana: No puedo iniciar sesión
La fila de arriba lee el argumento title, y la de abajo lee this.title después del trim. Si mueves la línea de label al principio del constructor, todavía no se ha asignado ni this.title ni this.customerName, así que label queda como undefined: undefined.
Declarar valores iniciales fijos — campos de clase
Todo ticket nuevo empieza con el estado «Pendiente» y cero comentarios. Si fijas estos valores iniciales, que no dependen de los argumentos, dentro del constructor con this.status = "Pendiente";, se mezclan con las líneas que guardan los argumentos, y para saber qué contiene una instancia tienes que leer todo el cuerpo.
Un campo de clase (una propiedad que se declara dentro de las llaves de la clase pero fuera del constructor y de los métodos, y que se agrega a la instancia en cada new) es solo un nombre y un valor inicial, sin this, como status = "Pendiente";. Para leerlo desde el cuerpo del constructor o desde un método, escribes this.status, igual que con cualquier otra propiedad.
class Ticket {
// Los valores iniciales que no dependen de los argumentos van en campos
status = "Pendiente";
comments = [];
constructor(title) {
this.title = title;
this.summary = `[${this.status}] ${title}`; // Aquí ya se pueden leer los campos
}
}
const first = new Ticket("No puedo iniciar sesión");
const second = new Ticket("Factura no recibida");
console.log(first.summary); // [Pendiente] No puedo iniciar sesión
// comments es un array distinto, creado en cada new
first.comments.push("Se pidió al cliente reiniciar");
console.log(first.comments.length); // 1
console.log(second.comments.length); // 0
new, primero se agregan los campos y después se ejecuta el cuerpo del constructor. El cuerpo ya puede leer los valores de los campos.El paso ① se repite en cada new, así que comments = [] es un array distinto para cada instancia, y un comentario agregado a first no aparece en second. Por eso second.comments.length sigue en 0.
Escribir this. en un campo es un SyntaxError
Si escribes this.status = "Pendiente"; donde van los campos (fuera del constructor), obtienes SyntaxError: Unexpected token '.' y no se ejecuta ni una línea. Agregar let o const también es un SyntaxError. Un campo es solo un nombre y un valor inicial.
El valor cuando se omite un argumento — parámetros por defecto
La mayoría de los tickets tiene prioridad «Normal», y quieres pasar «Urgente» solo cuando algo corre prisa. Si escribes el campo priority = "Normal"; y además agregas this.priority = priority; al cuerpo, un ticket creado sin prioridad no termina con «Normal».
Los parámetros por defecto (la sintaxis que fija el valor que se usa cuando no se pasa un argumento), que viste en el artículo sobre parámetros por defecto y parámetros rest, también funcionan en un constructor: escribe priority = "Normal" en la lista de parámetros. Un argumento omitido o undefined se reemplaza por el valor por defecto antes de que se ejecute el cuerpo, así que this.priority = priority recibe «Normal».
// Un valor por defecto en el campo y, además, asignar el argumento en el cuerpo
class DraftTicket {
priority = "Normal";
constructor(title, priority) {
this.title = title;
this.priority = priority; // El priority de la derecha es el argumento (undefined si se omite)
}
}
console.log(new DraftTicket("No puedo iniciar sesión").priority); // undefined
// Si un argumento puede cambiar el valor, pon el valor por defecto en un parámetro por defecto
class Ticket {
constructor(title, priority = "Normal") {
this.title = title;
this.priority = priority;
}
}
console.log(new Ticket("No puedo iniciar sesión").priority); // Normal
console.log(new Ticket("Factura no recibida", "Urgente").priority); // Urgente
undefined del argumento. Al final queda el valor asignado en el cuerpo.Los valores que un argumento puede cambiar van en parámetros por defecto, y los que no dependen de los argumentos, en campos. Para un valor que depende de una condición sobre los argumentos, como el costo de envío del Ejercicio 2, usa un if en el cuerpo para cambiar el valor inicial del campo. La tabla de abajo muestra qué queda en priority con cada forma, con y sin «Urgente», incluida una versión que nunca lo asigna en el cuerpo.
| Forma | Solo el título | Con "Urgente" |
|---|---|---|
| Solo campo (sin asignar en cuerpo) | Normal | Normal (se ignora) |
| Campo + this.priority = priority | undefined | Urgente |
| Por defecto: priority = "Normal" | Normal | Urgente |
Rechazar valores inválidos — throw en el constructor
Si terminas con un ticket que tiene el título vacío, o una prioridad que no es uno de los valores acordados, como «Alta», la lista muestra una fila en blanco y el ticket queda fuera cuando cuentas los «Urgente». Aunque escribas una función aparte para revisar los tickets después de crearlos, cualquier pantalla que se olvide de llamarla sigue usando la instancia inválida.
Para la validación al crear (comprobar, en el momento de crear una instancia, que los valores recibidos cumplen las reglas), escribe un if dentro del constructor y lanza una excepción con throw new Error(...) cuando un valor no cumpla. Una vez lanzada la excepción, la expresión new no devuelve ninguna instancia.
class Ticket {
constructor(title, priority = "Normal") {
// Rechaza los valores inválidos con una excepción antes de que lleguen a this
if (title.trim() === "") {
throw new Error("El título está vacío");
}
if (priority !== "Normal" && priority !== "Urgente") {
throw new Error(`La prioridad debe ser Normal o Urgente: ${priority}`);
}
this.title = title.trim();
this.priority = priority;
}
}
try {
const ticket = new Ticket("No puedo iniciar sesión", "Alta");
console.log(ticket.title); // Esta línea nunca se ejecuta
} catch (error) {
console.log(error.message); // La prioridad debe ser Normal o Urgente: Alta
}
const ticket = new Ticket(...): el lado derecho lanza la excepción yticketno recibe nadaconsole.log(ticket.title): nunca se ejecuta
- Revisión del título: no está vacío, así que pasa
- Revisión de la prioridad: es
"Alta", así que ejecutathrow this.title = ...: de aquí para abajo no se ejecuta nada
error.message: «La prioridad debe ser Normal o Urgente: Alta»
new, se salta el resto del try y llega a catch. La instancia inválida nunca queda en ninguna variable.Con la validación en el constructor, ningún ticket puede saltársela, sin importar en cuántos lugares se llame a new Ticket(...). Si incluyes el valor rechazado en el mensaje de la excepción, el lado del catch también puede mostrar qué valor era inválido.
Las asignaciones después de crear la instancia no se validan
La validación del constructor solo se ejecuta durante new. Si asignas ticket.priority = "Alta"; después de crear el ticket, no se produce ningún error y el valor simplemente se sobrescribe. Cómo validar el valor en cada asignación lo verás en el artículo sobre getters y setters.
Verificación de conocimientos
Responde cada pregunta una a una.
Pregunta 2Una clase tiene solo el campo priority = "Normal"; y no lo asigna en el cuerpo. ¿Qué pasa si pasas «Urgente» al crear la instancia?
Pregunta 3Dentro de un try, el constructor lanza una excepción durante const ticket = new Ticket(""). ¿Qué pasa?