La herencia es una característica que permite crear nuevas clases basadas en clases existentes.
Con la herencia, una clase puede disponer de las propiedades y métodos de otra, a la vez que añade o sobreescribe, con sus propios métodos.
Esta relación entre clases se conoce como relación padre-hijo o superclase-subclase.
En JavaScript, la herencia se implementa principalmente a través de clases, que fueron introducidas en ECMAScript 6 (ES6).
Antes de ES6, JavaScript utilizaba funciones constructoras y el objeto prototype
para implementar la herencia. Con la introducción de la sintaxis de clases, la herencia se volvió más sencilla y clara.
Si quieres aprender más puedes consultar
Sintaxis básica de la herencia
En JavaScript para crear una subclase que herede de la clase base, usamos la palabra clave extends
.
En primer lugar necesitamos definir una clase base, y a continuación crearíamos la clase derivada. Por ejemplo así,
class Animal {
constructor(nombre) {
this.nombre = nombre; // Propiedad compartida
}
hablar() {
console.log(`${this.nombre} hace un sonido`);
}
}
class Perro extends Animal {
constructor(nombre, raza) {
super(nombre); // Llama al constructor de la clase padre
this.raza = raza; // Propiedad adicional
}
hablar() {
console.log(`${this.nombre} dice ¡Guau!`);
}
}
const miPerro = new Perro('Rex', 'Labrador');
miPerro.hablar(); // "Rex dice ¡Guau!"
En este ejemplo:
Animal
es la clase base que tiene un constructor que asigna un valor anombre
y un método llamadohablar()
.Perro
es una subclase que hereda deAnimal
. Usa el métodosuper()
para llamar al constructor de la clase base y asignar el valor anombre
.- Además, sobrescribe el método
hablar()
para personalizar el comportamiento específico de los perros.
Palabra clave super
La palabra clave super()
nos permite obtener una referencia a la clase base, desde la clase derivada. Por ejemplo, sirve para,
- Llamar al constructor de la superclase: Cuando necesitamos inicializar las propiedades heredadas desde la clase base.
- Acceder a los métodos de la superclase: Para hacer uso de métodos de la superclase dentro de la subclase.
class Perro extends Animal {
constructor(nombre, raza) {
super(nombre); // Llama al constructor de la clase padre
this.raza = raza; // Propiedad adicional
}
}
En el ejemplo anterior,
super(nombre)
llama al constructor deAnimal
y pasa el argumentonombre
para que la propiedadnombre
sea inicializada.
Propiedades y métodos heredados
Cuando una subclase hereda de una superclase, hereda sus propiedades y métodos. Esto significa que podemos acceder a las propiedades y métodos de la superclase como si estuvieran definidos directamente en la subclase.
class Animal {
constructor(nombre) {
this.nombre = nombre;
}
hablar() {
console.log(`${this.nombre} hace un sonido`);
}
}
class Gato extends Animal {
// No es necesario redefinir 'nombre', ya que se hereda de Animal
}
const miGato = new Gato('Whiskers');
miGato.hablar(); // "Whiskers hace un sonido"
Aquí, Gato
hereda el método hablar()
de Animal
y lo puede utilizar sin tener que volver a definirlo.
Sobrescribir métodos en la subclase
Una característica de la herencia es que podemos sobrescribir los métodos de la clase base en la subclase. Esto nos permite personalizar el comportamiento.
Esto es útil cuando queremos que las subclases tengan comportamientos específicos, mientras conservamos la base de la clase original.
class Gato extends Animal {
hablar() {
console.log(`${this.nombre} dice ¡Miau!`);
}
}
const miGato = new Gato('Rufus el gato');
miGato.hablar(); // "Rufus el gato dice ¡Miau!"
En este caso, Gato
redefine el método hablar()
para que emita un sonido diferente al del Animal
.
Propiedades estáticas y herencia
Las subclases también heredan las propiedades estáticas. La clase base y la clase derivada comparten las variables y métodos estáticos (la clase derivada no tiene sus propias versiones)
class Animal {
static especie = 'Animal'; // Propiedad estática
//... más cosas
}
class Perro extends Animal {}
console.log(Perro.especie); // "Animal"
Perro.especie = "Perraco";
console.log(Animal.especie); // "Perraco"
Aquí,
- La propiedad estática
especie
es heredada por la subclasePerro
. - Si accedemos a
Perro.especie
obtenemosAnimal
. - Cuando modificamos
Perro.especie
, también modificamosAnimal.especie
. - Es decir, la propiedad
especie
es la misma para ambas clases.
¿Qué es el polimorfismo?
En otras palabras, el polimorfismo permite que los objetos de diferentes clases tengan diferentes comportamientos para el mismo método.
En JavaScript, el polimorfismo se puede lograr utilizando la herencia y la sobrescritura de métodos. Vamos a verlo con un ejemplo:
let animal = new Animal('Animal');
let cat = new Cat('Gato');
let dog = new Dog('Perro');
animal.makeSound(); // Haciendo sonido...
cat.makeSound(); // Miau!
dog.makeSound(); // Guau!
class Animal {
constructor(name) {
this.name = name;
}
makeSound() {
console.log('Haciendo sonido...');
}
}
class Cat extends Animal {
constructor(name) {
super(name);
}
makeSound() {
console.log('Miau!');
}
}
class Dog extends Animal {
constructor(name) {
super(name);
}
makeSound() {
console.log('Guau!');
}
}
En este ejemplo,
- Tenemos una clase Animal con un método
makeSound()
. - La clase
Cat
y la claseDog
heredan de la claseAnimal
y sobrescriben el métodomakeSound()
con sus propias implementaciones. - Cuando se llama al método
makeSound()
en cada objeto, el comportamiento es diferente según la clase de objeto.