Una clase que parte de otra
La herencia en JavaScript permite que una clase arranque desde el "plano" de otra y lo amplíe. Heredas todos los campos y métodos de la clase padre sin escribir una sola línea extra, y encima puedes sumar lo que quieras o cambiar lo que no te convenza:
Dog extends Animal se lee así: "un Dog es un Animal, con algo extra". rex no tiene un método speak propio, pero la búsqueda sube hasta Animal, que sí lo define. Ese "subir en la cadena" es todo el truco: herencia prototípica de toda la vida, solo que con una sintaxis más cómoda.
super en el constructor de una subclase
Si una subclase define su propio constructor, hay una regla innegociable: llamar a super(...) antes de tocar this. super ejecuta el constructor de la clase padre, que es quien realmente crea e inicializa el objeto:
Si te saltas la línea super(name), vas a recibir un ReferenceError en cuanto intentes leer o escribir this. El motor sencillamente se niega a entregarte un this hasta que la clase padre haya hecho lo suyo.
Cuando una subclase no declara su propio constructor, JavaScript genera uno automáticamente que reenvía todos los argumentos a super. Por eso solo hace falta escribirlo cuando vas a agregar campos nuevos o realizar alguna inicialización extra.
Sobrescribir métodos en JavaScript
Una subclase puede redefinir cualquier método que haya heredado. En la cadena de prototipos manda siempre el más cercano:
Aquí no hay magia: cuando llamas a speak() sobre un Dog, el motor busca speak primero en la instancia, después en Dog.prototype, lo encuentra y se detiene. Nunca llega a Animal.prototype.
Ampliar en vez de reemplazar: super.method()
A veces no quieres reemplazar el método del padre, sino ampliarlo. Con super.method(...) puedes invocar la versión del padre desde dentro del método sobrescrito:
Aquí es donde la herencia en JavaScript demuestra su valor: la subclase reutiliza la lógica del padre en vez de duplicarla. Si más adelante cambias Animal.describe, Dog.describe hereda ese cambio sin que tengas que tocar nada.
super no es exclusivo del constructor: funciona dentro de cualquier método. Siempre apunta a la versión del método definida en la clase padre.
instanceof y la cadena de prototipos
instanceof comprueba si la cadena de prototipos de un objeto incluye una clase determinada. Cada instancia de una subclase también es instancia de sus clases padre:
Los cuatro dan true. La cadena es Puppy -> Dog -> Animal -> Object, e instanceof la recorre entera. Viene bien para comprobar tipos, aunque en la práctica la vas a usar menos de lo que crees: casi siempre basta con llamar al método y dejar que el polimorfismo haga su trabajo.
Un ejemplo algo más completo
Un patrón muy habitual: una clase base con la lógica común y un par de subclases que la especializan.
Fíjate en que describe vive en Shape y nunca hace falta reescribirlo: simplemente llama a this.area(), que en tiempo de ejecución se resuelve a la subclase correspondiente. Eso es polimorfismo: la misma llamada, distinto comportamiento según el objeto real.
Herencia vs composición en JavaScript
La herencia resulta tentadora porque da sensación de productividad: con una línea heredas un montón de métodos. El problema es que envejece mal cuando las jerarquías empiezan a crecer.
Regla práctica: usa extends cuando la relación sea claramente "X es un Y" y la subclase comparta de verdad la mayoría del comportamiento del padre. Si estás recurriendo a la herencia solo para compartir uno o dos métodos auxiliares, mejor tira de composición: dale a la clase un campo que contenga ese objeto auxiliar:
Los árboles de herencia muy profundos (Animal -> Mammal -> Dog -> WorkingDog -> PoliceDog) quedan preciosos en un diagrama, pero en el código son un dolor de cabeza: cualquier cambio cerca de la raíz se propaga de forma impredecible por todos los descendientes. La mayoría de los proyectos sanos se quedan en uno o dos niveles de profundidad y resuelven el resto con composición.
Siguiente paso: miembros estáticos
Todo lo que hemos visto en este documento vive en las instancias: métodos que invocas con new Thing().something(). Pero a veces necesitas métodos o datos que pertenezcan a la clase misma, no a una instancia concreta. Para eso existe static, y es justo lo que vamos a ver a continuación.
Preguntas frecuentes
¿Cómo funciona la herencia en JavaScript?
Una clase puede heredar de otra con extends. La subclase recibe todos los métodos y campos de la clase padre, y puede añadir los suyos propios o sobrescribir los existentes. Por dentro, JavaScript enlaza el prototipo de la subclase con el de la clase padre, así que la búsqueda de métodos cae hacia arriba de forma automática.
¿Qué hace super en JavaScript?
super(...) llama al constructor de la clase padre, y hay que invocarlo antes de usar this dentro del constructor de una subclase. super.metodo(...) llama a la versión del método que tiene la clase padre, que es la forma de extender su comportamiento en vez de reemplazarlo por completo.
¿Herencia o composición en JavaScript?
Usa herencia cuando haya una relación real de tipo 'es un' y la subclase comparta la mayor parte del comportamiento del padre. Tira de composición —objetos que contienen otros objetos— cuando solo quieras reutilizar funcionalidad. Las jerarquías de clases muy profundas envejecen mal; la mayoría de los proyectos reales se quedan en uno o dos niveles.