Herencia en Clases
Las clases en JavaScript permiten hereda propiedades y métodos de una clase padre. A este proceso se le llama herencia. Es posible que todo esto te suene familiar, porque ya lo has visto en la clase anterior cómo conseguirlo con los prototipos, pero ahora veremos cómo lograrlo con clases.
extends
La principal ventaja de las clases es que simplifican enormemente la herencia de objetos gracias a la palabra clave extends
. Vamos a crear una clase Animal
, que será la clase padre, y una clase Perro
, que será la clase que herede de Animal
.
class Animal {
constructor(nombre) {
this.nombre = nombre
}
dormir() {
console.log(`${this.nombre} está durmiendo`)
}
}
class Perro extends Animal {
constructor(nombre, raza) {
super(nombre) // Llama al constructor del padre
this.raza = raza
}
ladrar() {
console.log(`${this.nombre} dice: ¡Guau!`)
}
}
const rex = new Perro('Rex', 'Labrador')
rex.dormir() // "Rex está durmiendo" (heredado)
rex.ladrar() // "Rex dice: ¡Guau!" (propio)
De esta forma, la clase Perro
hereda el método dormir
de la clase Animal
y añade el método ladrar
.
La palabra clave super
Como hemos visto en el ejemplo anterior, hay una palabra super
en el método constructor de la clase Perro
. Esta función se usa para llamar al constructor de la clase padre y también nos permite acceder a los métodos y propiedades de la clase padre.
class Vehiculo {
acelerar() {
console.log('Acelerando...')
}
}
class Moto extends Vehiculo {
acelerar() {
super.acelerar() // Llama al método del padre
console.log('¡Haciendo caballito!') // Añade funcionalidad
}
}
const moto = new Moto()
moto.acelerar()
// "Acelerando..."
// "¡Haciendo caballito!"
Ejemplo práctico de herencia
Veamos un ejemplo más completo que muestra cómo funciona la herencia en la práctica. Tenemos una clase Empleado
, que será la clase padre, y las clases Programador
y Manager
, que serán las clases que hereden de Empleado
. Normalmente las clases hijas suelen tener métodos y propiedades propias y más específicos.
class Empleado {
constructor(nombre, salario) {
this.nombre = nombre
this.salario = salario
}
trabajar() {
console.log(`${this.nombre} está trabajando`)
}
cobrar() {
console.log(`${this.nombre} cobra ${this.salario}€`)
}
}
class Programador extends Empleado {
constructor(nombre, salario, lenguaje) {
super(nombre, salario) // Llama al constructor padre
this.lenguaje = lenguaje
}
// Sobrescribe el método del padre
trabajar() {
super.trabajar() // Llama al método padre
console.log(`Programando en ${this.lenguaje}`)
}
// Método propio
programar() {
console.log(`${this.nombre} está programando en ${this.lenguaje}`)
}
}
class Manager extends Empleado {
constructor(nombre, salario, equipo) {
super(nombre, salario)
this.equipo = equipo
}
trabajar() {
super.trabajar()
console.log(`Gestionando un equipo de ${this.equipo.length} personas`)
}
dirigir() {
console.log(`${this.nombre} está dirigiendo el equipo`)
}
}
const dev = new Programador('Ana', 45000, 'JavaScript')
const jefe = new Manager('Carlos', 60000, ['Ana', 'Luis', 'María'])
dev.trabajar()
// "Ana está trabajando"
// "Programando en JavaScript"
jefe.trabajar()
// "Carlos está trabajando"
// "Gestionando un equipo de 3 personas"
dev.cobrar() // "Ana cobra 45000€" (heredado)
jefe.dirigir() // "Carlos está dirigiendo el equipo" (propio)
Cadenas de herencia
Podemos crear cadenas de herencia más complejas donde una clase herede de otra que ya hereda de una tercera:
class SerVivo {
constructor(nombre) {
this.nombre = nombre
this.vivo = true
}
respirar() {
console.log(`${this.nombre} está respirando`)
}
}
class Animal extends SerVivo {
constructor(nombre, especie) {
super(nombre)
this.especie = especie
}
moverse() {
console.log(`${this.nombre} se está moviendo`)
}
}
class Mamifero extends Animal {
constructor(nombre, especie, pelaje) {
super(nombre, especie)
this.pelaje = pelaje
}
amamantar() {
console.log(`${this.nombre} está amamantando`)
}
}
class Gato extends Mamifero {
constructor(nombre, raza) {
super(nombre, 'Felino', true)
this.raza = raza
}
maullar() {
console.log(`${this.nombre} dice: ¡Miau!`)
}
}
const michi = new Gato('Michi', 'Persa')
// Puede usar métodos de todas las clases padre
michi.respirar() // De SerVivo
michi.moverse() // De Animal
michi.amamantar() // De Mamifero
michi.maullar() // Propio de Gato
Ventajas de la herencia con clases
Comparado con funciones constructoras:
- ✅ Sintaxis más clara:
extends
vs configuración manual de prototipos - ✅ Super simplificado:
super()
vsParent.call(this)
- ✅ Menos propenso a errores: JavaScript maneja la cadena de prototipos automáticamente
- ✅ Más legible: El código expresa claramente las relaciones de herencia
Lo importante recordar:
- Las clases son azúcar sintáctico sobre prototipos
- La herencia sigue funcionando igual por debajo
super()
debe llamarse antes de usarthis
en el constructor hijo- Los métodos se heredan automáticamente a través de la cadena de prototipos
La herencia con clases hace que JavaScript sea más accesible para desarrolladores de otros lenguajes, manteniendo toda la potencia de los prototipos. 🚀