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}%`); }}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
- fleet es un array: 2 coches normales y 2 eléctricos.
- c apunta al Skoda: instanceof da «no». El cuerpo del if se salta.
- c apunta al Tesla: instanceof da «sí». No hace falta una variable nueva: c.charge() carga el mismo coche.
- c apunta al Dacia: instanceof da «no». El cuerpo del if se salta.
- c apunta al Nissan: instanceof da «sí». No hace falta una variable nueva: c.charge() carga el mismo coche.
- 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);Un coche eléctrico también es un coche, así que la primera comprobación es verdadera. La comprobación no pregunta «¿es exactamente un Car?», sino «¿se puede usar este objeto como un Car?». El coche normal d no es eléctrico, así que la última comprobación es falsa.
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);ElectricCarfalsetruetrue falsenumber string boolean objectc.constructores la clase con la que se creó el objeto, yc.constructor.namees su nombre.c.constructor === Carpregunta «¿es exactamente unCar?» y para el coche eléctrico esfalse, mientras quec instanceof Carestrue. Casi siempre quieresinstanceof: 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 concharge().typeofda 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 usasinstanceof.
Más precisamente, para curiosos
- La comprobación siempre es falsa para
null:null instanceof Caresfalse. Así que después de uninstanceofque sale bien nunca tienesnull. - No puedes usar
instanceofpara preguntar por un contrato: un contrato son solo nombres de métodos, y no hay ninguna clase con la que comparar. Para eso usastypeof 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:
Normales: 4, eléctricos: 0¿En qué línea está el error?
Elige la línea con el error.
Todo coche eléctrico también es un Car, así que la primera comprobación es verdadera para los cuatro coches. El programa nunca llega a la segunda. Comprueba primero el tipo más concreto: si es un ElectricCar, cuéntalo como eléctrico, si no, como normal.
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 Carenergy() { return "gasolina";}
// en ElectricCarenergy() { return "electricidad";}for (const c of fleet) { console.log(`${c.brand}: ${c.energy()}`);}Skoda: gasolinaTesla: electricidadDacia: gasolinaNissan: electricidadMañ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();
}
}instanceof: comprueba si c apunta a un ElectricCar. Si es así, c.charge() funciona.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.
Accountguarda el saldo #privado y ofrece solodeposit()ywithdraw(). Encapsulamiento - Herencia. Lo común está en un solo lugar, la clase padre, y la clase hija añade lo suyo.
Manageres unEmployeecon 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
Shapepromete 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.
Esto es un SimpleCarEsto es un FamilyCarEsto es un SimpleCar2. 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.
moonwalk: DanceMovewindmill: BreakDanceMove, complejidad 8salsa: DanceMove3. 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.
Skoda: 100 km, combustible 30 lTesla: 100 km, batería 80%El combustible no alcanza para 100 kmDacia: 0 km, combustible 5 lNissan: 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.
¡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
Lecciones relacionadas
Sección «Lecciones relacionadas»- Se basa en: Herencia · Polimorfismo · Clases abstractas sin abstract · Interfaces sin interface
- Continúa en: Principios de la POO · Lanzar excepciones y crear las tuyas · Códigos hash y funciones hash · Datos, switch y desestructuración
- Ejercicios sobre el tema: Herencia y polimorfismo