Ir al contenido
wannacode

Clases y objetos

En resumen: Una clase describe un tipo nuevo con campos, y un objeto es una instancia concreta de ella, creada con new; la variable solo apunta al objeto.

Problema

Los precios se mezclaron

Estás escribiendo el carrito de una tienda en línea. Cada producto tiene un nombre y un precio, así que los guardas en dos arrays. El índice 0 guarda el nombre y el precio del primer producto, el índice 1 los del segundo.

Quieres el más caro primero, así que intercambias los precios:

const names = ["Pan", "Leche", "Café"];
const prices = [1.20, 2.10, 7.50];
// Lo más caro primero: intercambiamos el primer y el tercer precio.
const temp = prices[0];
prices[0] = prices[2];
prices[2] = temp;
for (let i = 0; i < names.length; i++) {
console.log(`${names[i]}: ${prices[i]} €`);
}
Salida
Pan: 7.5 €
Leche: 2.1 €
Café: 1.2 €

Ahora el pan cuesta 7,50 €. Los precios se intercambiaron, pero los nombres no. Los dos arrays siempre tienen que cambiar juntos, pero nada te obliga a hacerlo. Añade un tercer array para las cantidades, y tendrás que vigilar tres.

La idea

Un producto, un lugar

El nombre y el precio no son cosas separadas. Son partes de un producto. Queremos un tipo «producto», igual que existe number para los números y string para el texto.

Un tipo así lo creas tú mismo. Se llama clase:

class Product {
name;
price;
quantity;
}

Las variables de la clase son sus campos. Cada producto tendrá su propio nombre, su propio precio y su propia cantidad.

La clase es solo una descripción: «cada producto tiene un nombre, un precio y una cantidad». Todavía no hay ningún producto.

El nombre de la clase empieza con mayúscula (Product), y los nombres de los campos con minúscula (name, price). Así ves enseguida qué es un tipo y qué es un valor.

La idea

new: de la descripción a un producto

Creas un producto concreto a partir de la clase con new. Se llama objeto. Llegas a sus campos con un punto:

shop.js
class Product {
name;
price;
quantity;
}
const bread = new Product();
bread.name = "Pan";
bread.price = 1.20;
bread.quantity = 2;
const coffee = new Product();
coffee.name = "Café";
coffee.price = 7.50;
coffee.quantity = 1;
console.log(`${bread.name}: ${bread.price * bread.quantity} €`);
console.log(`${coffee.name}: ${coffee.price * coffee.quantity} €`);
Salida
Pan: 2.4 €
Café: 7.5 €
  • La clase está encima del código que la usa. Un archivo puede tener varias clases.
  • new Product() crea un objeto nuevo. Cada objeto tiene sus propios campos: el pan y el café no se estorban.
  • bread.price es «el precio del pan». Lo lees y lo escribes como una variable normal.
  • const bread significa que bread siempre apunta al mismo objeto. Los campos del objeto sí pueden cambiar.

Ahora el nombre y el precio del producto están en un solo lugar. Mueves el producto, y se mueven juntos.

Pruébalo

No se ha rellenado nada

Si creas un producto y no rellenas nada, ¿qué hay en sus campos?

¿Qué imprimirá el programa?

const item = new Product();
console.log(item.name);
console.log(item.price);
console.log(item.quantity);
Respuesta

Pruébalo

¿Qué falta?

¿Qué va en el hueco para que haya un producto nuevo?

const milk =  Product();
milk.name = "Leche";
milk.price = 2.10;

Míralo

La variable apunta al objeto

Quieres una oferta de café, así que haces una «copia» para cambiarle el precio:

const coffee = new Product();
coffee.price = 10;
const sale = coffee;
sale.price = 8;
console.log(coffee.price); // 8
Paso a paso, en palabras
  1. new crea el objeto, y sus campos todavía son undefined. coffee recibe una flecha hacia él.
  2. Por la flecha de coffee: el precio del objeto pasa a ser 10.
  3. sale = coffee copia la flecha, no el objeto. Dos flechas, un objeto.
  4. Por la flecha de sale: el precio del mismo objeto pasa a ser 8.
  5. coffee apunta al mismo objeto, así que imprime 8.

El precio del café también pasó a ser 8. La razón es que la variable coffee no es el objeto en sí. El objeto vive aparte en la memoria, y coffee guarda dónde está: una flecha al objeto. Una variable así se llama referencia.

sale = coffee copia la flecha, no el objeto. Ahora dos flechas apuntan a un objeto, así que el cambio a través de sale se ve también a través de coffee.

Ya viste lo mismo en la lección sobre arrays: sale = prices le daba un segundo nombre al mismo array. Un array también es un objeto.

La idea

Ahora el descuento funciona

En el módulo «Funciones», el descuento no funcionaba: la función recibía el precio, cambiaba su propio parámetro, y el cambio se perdía. Con un objeto es distinto:

function discount(p, percent) {
p.price = p.price * (100 - percent) / 100;
}
const coffee = new Product();
coffee.price = 10;
discount(coffee, 10);
console.log(coffee.price);
Salida
9

El parámetro sigue siendo una copia, pero una copia de la flecha. Apunta al mismo objeto, así que el cambio de p.price se queda también después de la función.

Más precisamente, para curiosos

Si la función pone un objeto nuevo en el parámetro, solo mueve su propia copia de la flecha. El objeto de fuera no cambia:

function reset(p) {
p = new Product();
p.price = 0;
}
const coffee = new Product();
coffee.price = 10;
reset(coffee);
console.log(coffee.price);
Salida
10
Por eso se dice que JavaScript pasa todo por valor, y para los objetos el valor es la referencia.

La idea

null: una flecha a ninguna parte

Una variable puede no apuntar a ningún objeto. Entonces guarda null: «nada». Si intentas leer un campo a través de ella, no hay ningún objeto del que leerlo:

const gift = null;
console.log(gift.name);

El programa arranca, pero se detiene con un error cuando llega a la línea:

Error
TypeError: Cannot read properties of null (reading 'name')

Es el error más común con objetos. Qué es una «excepción» y cómo se captura, lo verás en el módulo «Errores y excepciones».

Un array también guarda flechas, no los productos mismos. new Array(3).fill(null) crea tres lugares que todavía no apuntan a ningún producto. Cada uno es null hasta que pones ahí new Product():

const cart = new Array(3).fill(null);
console.log(cart[0] === null);
cart[0] = new Product();
cart[0].name = "Pan";
console.log(cart[0].name);
Salida
true
Pan

Pruébalo

Encuentra el error

El programa debería imprimir «Pan» y «Leche». En cambio, imprime «Leche» dos veces. ¿Qué línea tiene el error?

Elige la línea con el error.

Ejercicio

Tus clases

Resuelve las tareas en tu editor. La clase va al principio del archivo, y los objetos los creas en el código de debajo.

1. Libro. Una clase Book con campos para el título y el autor. Crea dos libros e imprímelos.

Salida
Cien años de soledad de Gabriel García Márquez
Rayuela de Julio Cortázar

2. Coche. Una clase SimpleCar con un campo para la velocidad. Crea un coche (su velocidad es 0), aumenta la velocidad en 10 e imprímela. Dale al campo un valor inicial (speed = 0;): sin él, undefined + 10 da NaN, «no es un número». En la lección «Métodos de instancia» esto se convertirá en un método del coche.

Salida
Velocidad tras acelerar: 10

3. El carrito. El carrito de la primera tarjeta, esta vez con un array de tres objetos Product: pan 1,20 € (2 uds.), leche 2,10 € (1 ud.), café 7,50 € (1 ud.). Imprime el importe de cada línea y el total. Crea primero cada producto con new Product(), y después ponlo en el array.

Salida
Pan x2: 2.4 €
Leche x1: 2.1 €
Café x1: 7.5 €
Total: 12 €

4. El más caro primero. Ordena el mismo carrito por precio, del más caro al más barato, con el ordenamiento de burbuja de la lección sobre arrays. Esta vez intercambias productos enteros, así que el nombre y el precio se mueven juntos.

Salida
Café: 7.5 €
Leche: 2.1 €
Pan: 1.2 €

Más tareas

  • Estudiante. Una clase Student con un nombre y tres notas (tres campos). Crea dos estudiantes e imprime la nota media de cada uno.
  • Un libro, dos nombres. Crea un libro, guárdalo en dos variables y cambia el título a través de la segunda. Imprime el título a través de la primera. Explica con palabras por qué funciona así.

Test

Ponte a prueba

1. ¿Cuál es la diferencia entre una clase y un objeto?
2. const sale = coffee; sale.price = 8; ¿Qué pasa con el precio del café?
3. ¿Qué hay en el array justo después de const cart = new Array(3).fill(null);?
4. Una función recibe un producto como parámetro y cambia su precio. ¿Se ve el cambio después de la llamada?
5. const gift = null; ¿Qué pasa en gift.name?

Creado por Ivo Gergov como parte de la campaña de Evo Tech por una educación accesible en programación ·