Ir al contenido
wannacode

Comprobaciones de tipo

En resumen: Una comprobación de tipo con instanceof pregunta si un objeto es de una clase dada o de una de sus clases hijas, y typeof dice el tipo de un valor simple.

Problema

Solo algunos se pueden cargar

Una empresa tiene una flota de coches normales y eléctricos. Cada noche hay que cargar los eléctricos. ElectricCar hereda de Car y añade charge(), así que todos están en un solo array:

const fleet = [
new Car("Skoda"),
new ElectricCar("Tesla", 35),
new Car("Dacia"),
new ElectricCar("Nissan", 60),
];
for (const c of fleet) {
c.charge();
}

El programa arranca y se detiene en el primer coche, «Skoda»: TypeError: c.charge is not a function. Nunca llega a los eléctricos.

Un coche normal de verdad no se puede cargar. Tienes que preguntar a cada coche: «¿eres eléctrico?»

La idea

Pregunta al objeto qué es

for (const c of fleet) {
if (c instanceof ElectricCar) {
c.charge();
console.log(`${c.brand}: cargado al ${c.battery}%`);
}
}
Salida
Tesla: cargado al 100%
Nissan: cargado al 100%

c instanceof ElectricCar pregunta al objeto al que apunta c: «¿eres un ElectricCar?» y da true o false. Esto se llama comprobación de tipo.

No necesitas una variable nueva. En JavaScript las variables no tienen tipo, así que no hay nada que convertir: en cuanto la comprobación es verdadera, c apunta a un coche eléctrico y c.charge() funciona. Los coches siguen siendo los mismos.

for (const c of fleet) {
if (c instanceof ElectricCar) {
c.charge();
console.log(`${c.brand}: cargado al ${c.battery}%`);
}
}
Paso a paso, en palabras
  1. fleet es un array: 2 coches normales y 2 eléctricos.
  2. c apunta al Skoda: instanceof da «no». El cuerpo del if se salta.
  3. c apunta al Tesla: instanceof da «sí». No hace falta una variable nueva: c.charge() carga el mismo coche.
  4. c apunta al Dacia: instanceof da «no». El cuerpo del if se salta.
  5. c apunta al Nissan: instanceof da «sí». No hace falta una variable nueva: c.charge() carga el mismo coche.
  6. Los coches no cambian. La comprobación solo pregunta al objeto qué es.

Pruébalo

¿Es un coche?

¿Qué imprimirá el programa?

const c = new ElectricCar("Tesla", 35);
const d = new Car("Skoda");
console.log(c instanceof Car);
console.log(c instanceof ElectricCar);
console.log(d instanceof ElectricCar);
Respuesta

La idea

Otras formas con las que te encontrarás

Además de instanceof te encontrarás con algunas maneras más de preguntar a un objeto:

const c = fleet[1];
console.log(c.constructor.name);
console.log(c.constructor === Car);
console.log(c instanceof Car);
console.log(typeof c.charge === "function", typeof fleet[0].charge === "function");
console.log(typeof 42, typeof "Tesla", typeof true, typeof c);
Salida
ElectricCar
false
true
true false
number string boolean object
  • c.constructor es la clase con la que se creó el objeto, y c.constructor.name es su nombre. c.constructor === Car pregunta «¿es exactamente un Car?» y para el coche eléctrico es false, mientras que c instanceof Car es true. Casi siempre quieres instanceof: también acepta las clases hijas.
  • typeof c.charge === "function" no pregunta por la clase, solo si el objeto tiene un método así. Es la comprobación de contrato de la lección «Interfaces»: pasa cualquier objeto con charge().
  • typeof da el tipo de un valor como texto: "number", "string", "boolean", "function". Para todo objeto es "object", así que no te dice la clase. Para la clase usas instanceof.
Más precisamente, para curiosos
  • La comprobación siempre es falsa para null: null instanceof Car es false. Así que después de un instanceof que sale bien nunca tienes null.
  • No puedes usar instanceof para preguntar por un contrato: un contrato son solo nombres de métodos, y no hay ninguna clase con la que comparar. Para eso usas typeof a.swim === "function".

Pruébalo

Encuentra el error

El programa cuenta los coches normales y los eléctricos. La flota tiene dos de cada uno, pero imprime:

Salida
Normales: 4, eléctricos: 0

¿En qué línea está el error?

Elige la línea con el error.

La idea

¿Una comprobación o un método?

Quieres imprimir con qué funciona cada coche. Una comprobación de tipo puede hacerlo:

for (const c of fleet) {
if (c instanceof ElectricCar) {
console.log(`${c.brand}: electricidad`);
} else {
console.log(`${c.brand}: gasolina`);
}
}

Pero esto es el salario con un if por cada rol de la lección de polimorfismo. Todo coche tiene una fuente de energía, solo que distinta. Eso es trabajo para un método en Car, sobrescrito en ElectricCar:

// en Car
energy() {
return "gasolina";
}
// en ElectricCar
energy() {
return "electricidad";
}
for (const c of fleet) {
console.log(`${c.brand}: ${c.energy()}`);
}
Salida
Skoda: gasolina
Tesla: electricidad
Dacia: gasolina
Nissan: electricidad

Mañana llega un coche híbrido. Con el método, escribes una clase nueva. Con las comprobaciones, buscas cada if del programa.

La regla:

  • Todo objeto lo hace, cada uno a su manera: un método en la clase padre, y sobrescritura.
  • Solo algunos objetos pueden hacerlo (cargar, pedalear): una comprobación de tipo.

Pruébalo

¿Qué falta?

for (const c of fleet) {
  if (c  ElectricCar) {
    c.charge();
  }
}

En resumen

Los cuatro pilares de la POO

Con esta lección has visto todas las ideas de los módulos «Clases y objetos» y «Herencia y polimorfismo». La programación orientada a objetos se apoya en cuatro de ellas. Ya las usas todas:

  • Encapsulamiento. Los datos del objeto están ocultos, y desde fuera llegas a ellos solo a través de métodos que vigilan las reglas. Account guarda el saldo #privado y ofrece solo deposit() y withdraw(). Encapsulamiento
  • Herencia. Lo común está en un solo lugar, la clase padre, y la clase hija añade lo suyo. Manager es un Employee con un bono. Herencia
  • Polimorfismo. Una sola llamada, un comportamiento distinto según el objeto. e.monthlyPay() en un solo bucle calcula el pago de un empleado, un gerente y un becario. Polimorfismo
  • Abstracción. Dices qué tiene que saber hacer el objeto, y cada clase decide cómo. El abstracto Shape promete un área, el contrato de pago promete un importe a pagar. Clases abstractas, Interfaces

Cómo trabajan las cuatro juntas en un solo programa, cuándo duele cada una y qué se suele confundir está en la última lección del módulo: Principios de la POO.

Ejercicio

¿Qué es en realidad?

Resuélvelas en tu editor.

1. Aparcamiento. Un array de coches normales y familiares (FamilyCar hereda de SimpleCar). Para cada uno, imprime su tipo. Cuidado con el orden de las comprobaciones.

Salida
Esto es un SimpleCar
Esto es un FamilyCar
Esto es un SimpleCar

2. Bailes. Un array de pasos normales y de breakdance. Para los pasos de breakdance, imprime también la complejidad. Solo BreakDanceMove la tiene, así que pregunta por ella después de la comprobación.

Salida
moonwalk: DanceMove
windmill: BreakDanceMove, complejidad 8
salsa: DanceMove

3. Flota. Toma Car y ElectricCar del ejercicio de la lección «Herencia». En un array, pon un «Skoda» con 40 l, un «Tesla» con eficiencia 5, un «Dacia» con 5 l y un «Nissan» con eficiencia 4. Cada uno recorre 100 km: los eléctricos con driveElectric, los demás con drive. Después imprime los kilómetros y el combustible o la batería.

Salida
Skoda: 100 km, combustible 30 l
Tesla: 100 km, batería 80%
El combustible no alcanza para 100 km
Dacia: 0 km, combustible 5 l
Nissan: 100 km, batería 75%

4. Zoológico. Una clase abstracta Animal con sound(), y clases hijas Cat, Dog y Fish. Solo Fish tiene además swim(): cumple el contrato «sabe nadar». En un bucle sobre los animales, llama al sonido de cada uno, y para los que saben nadar, llama también a swim(). El contrato no tiene clase, así que la comprobación usa typeof.

Salida
¡Miau, miau!
¡Guau, guau!
El pez se calla.
El pez nada.

Más tareas

  • Pedales. En el ejercicio de la lección «Clases abstractas», garage[0].pedal() detenía el programa, porque ahí no hay una bicicleta. Arréglalo con una comprobación de tipo: en el bucle sobre los vehículos, todo vehículo arranca, y solo la bicicleta además pedalea.
  • Pagos por tipo. De la lección «Interfaces»: el array payments guarda empleados y facturas. Imprime por separado el total de salarios y el total de facturas. Para Juan, María y las dos facturas: 5500 € en salarios y 2140 € en facturas.

Test

Ponte a prueba

1. c instanceof ElectricCar es verdadero. ¿Cómo cargas el coche?
2. c apunta a un ElectricCar. ¿Qué da c instanceof Car?
3. Compruebas si un coche es un Car o un ElectricCar. ¿En qué orden?
4. El programa tiene muchos if del tipo «si es un ElectricCar, haz una cosa, si no, haz otra». ¿Qué te dice eso?
5. c apunta a un coche normal. ¿Qué pasa con c.charge(), sin ninguna comprobación antes?

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