JavaScript

JavaScript

Tutorial JavaScript: Herencia

JavaScript herencia: clases y ejemplos claros. Aprende a implementar herencia en clases de JavaScript con ejemplos claros y detallados.

En JavaScript, la herencia es un mecanismo que permite a los objetos heredar propiedades y métodos de otros objetos. La herencia en JavaScript es prototípica, lo que significa que se basa en el uso de prototipos en lugar de clases, como ocurre en otros lenguajes de programación basados en objetos, como Java o C#.

Prototipos y la cadena de prototipos

Para entender la herencia en JavaScript, es importante comprender primero el concepto de prototipo. En JavaScript, todos los objetos tienen una propiedad interna llamada [[Prototype]] (también accesible mediante __proto__), que hace referencia a otro objeto llamado "prototipo". Este objeto es esencialmente una plantilla desde la cual el objeto hereda propiedades y métodos.

Cuando se intenta acceder a una propiedad o método en un objeto, JavaScript busca primero en el objeto en sí. Si no encuentra esa propiedad o método, busca en el prototipo del objeto. Si aún no encuentra la propiedad o método, sigue buscando en el prototipo de ese prototipo, y así sucesivamente hasta llegar al final de la cadena de prototipos. Este proceso se conoce como "búsqueda de propiedades en la cadena de prototipos" y es el mecanismo principal que permite la herencia en JavaScript.

Creación de objetos y su relación con Prototipos

Existen diversas formas de crear objetos en JavaScript. A continuación se detallan las dos formas más comunes, que permiten establecer la relación de herencia entre objetos.

Funciones constructoras

Una función constructora es una función especial utilizada para crear objetos. Cuando se invoca a una función constructora con el operador new, crea un nuevo objeto y automáticamente establece su prototipo como el objeto al que apunta la propiedad prototype de la función constructora.

function Persona(nombre, edad) {
  this.nombre = nombre;
  this.edad = edad;
}

Persona.prototype.saludar = function() {
  console.log('Hola, mi nombre es ' + this.nombre);
}

const persona1 = new Persona('John', 28);
persona1.saludar(); // Hola, mi nombre es John

En este ejemplo, se crea una función constructora Persona que recibe dos argumentos nombre y edad. Luego, se agrega un método saludar al prototipo de Persona. Cuando se crea el objeto persona1, su prototipo se establece automáticamente como Persona.prototype, lo que permite que persona1 tenga acceso al método saludar.

Object.create()

La función Object.create() permite crear un nuevo objeto con un prototipo específico.

const persona = {
  saludar: function() {
    console.log('Hola, mi nombre es ' + this.nombre)
  }
}

const persona1 = Object.create(persona);
persona1.nombre = 'John';
persona1.saludar(); // Hola, mi nombre es John

En este ejemplo, se crea un objeto persona que representa un prototipo con un método saludar. Luego, se crea el objeto persona1 utilizando Object.create() y pasando el objeto persona como su prototipo, lo que permite que persona1 tenga acceso al método saludar.

Herencia en JavaScript: subtipos

Una vez entendido el funcionamiento de los prototipos, la herencia en JavaScript puede implementarse creando un subtipo de un objeto existente. Supóngase que se quire crear un objeto Estudiante que herede del objeto Persona creado anteriormente.

function Estudiante(nombre, edad, curso) {
  // Invocar al constructor de Persona para inicializar las propiedades 'nombre' y 'edad'
  Persona.call(this, nombre, edad);
  this.curso = curso;
}

// Establecer el prototipo de Estudiante como Persona.prototype
Estudiante.prototype = Object.create(Persona.prototype);
// Ajustar el constructor a Estudiante
Estudiante.prototype.constructor = Estudiante;

// Agregar un nuevo método a Estudiante.prototype
Estudiante.prototype.estudiar = function() {
  console.log(this.nombre + ' está estudiando ' + this.curso);
}

const estudiante1 = new Estudiante('Jane', 22, 'Matemáticas');
estudiante1.saludar(); // Hola, mi nombre es Jane
estudiante1.estudiar(); // Jane está estudiando Matemáticas

En este ejemplo, se crea una nueva función constructora llamada Estudiante. Dentro del constructor de Estudiante, se invoca al constructor de Persona mediante Persona.call(this, nombre, edad) para inicializar las propiedades nombre y edad del objeto estudiante. Luego, se establece el prototipo de Estudiante como Persona.prototype utilizando Object.create(). También es importante actualizar el constructor en Estudiante.prototype para asegurarse de que apunte correctamente al constructor Estudiante.

Una vez establecida la relación de herencia, se puede agregar un nuevo método estudiar al prototipo de Estudiante. Al crear un objeto estudiante1, este hereda propiedades y métodos tanto de Estudiante.prototype como de Persona.prototype.

Herencia de atributos y métodos

Cuando un objeto hereda de otro objeto o "prototipo" en JavaScript, obtiene acceso a todos los atributos y métodos definidos en el prototipo, así como a los atributos y métodos en los prototipos de niveles superiores en la cadena de prototipos.

Herencia de atributos

Los atributos son propiedades que caracterizan a un objeto. Un objeto puede heredar atributos de su prototipo mediante la relación de herencia establecida entre ellos. Al acceder a un atributo en un objeto que no está presente en él, JavaScript busca ese atributo en el prototipo y, si es necesario, en los niveles superiores de la cadena de prototipos hasta encontrar el atributo o llegar al final de la cadena implicando que el atributo no está definido.

En el caso de las funciones constructoras y las clases de ES6, es común heredar atributos mediante el llamado al constructor del objeto del cual se desea heredar utilizando NombreConstructor.call(this, argumentos) o super(argumentos) (en el caso de las clases).

Herencia de métodos

Los métodos son funciones asociadas a un objeto que definen su comportamiento. Al heredar métodos en JavaScript, estos se comparten entre todos los objetos instanciados que heredan del mismo prototipo, lo que ahorra memoria y evita la duplicación del código del método. La herencia de métodos se logra al definir métodos en el prototipo del objeto del cual se desea heredar en lugar de definirlos en el objeto en sí.

Al acceder a un método en un objeto que no está presente en él, JavaScript sigue la misma búsqueda en la cadena de prototipos que aplica para los atributos, hasta encontrar el método o llegar al final de la cadena. Debido a que los métodos heredados comparten contexto y acceden a sus propios atributos mediante this, es importante que los atributos en aquel objeto estén correctamente inicializados.

Herencia mediante 'extends' y 'super'

Con la introducción de ECMAScript 6 (ES6), JavaScript incorporó el concepto de clases, que en realidad es una envoltura alrededor de la herencia basada en prototipos. Aunque las clases no traen algo nuevo en cuanto a herencia en comparación con los prototipos, estas simplifican la sintaxis para utilizar la herencia y hacen que el código sea más fácil de leer y mantener.

Las palabras clave extends y super son valiosas en el uso de herencia en clases de JavaScript.

extends

La palabra clave extends en JavaScript permite establecer que una clase es un subtipo de otra clase, heredando sus atributos y métodos. Al utilizar extends, JavaScript se encarga automáticamente de establecer el prototipo y el constructor apropiado.

class Persona {
  constructor(nombre, edad) {
    this.nombre = nombre;
    this.edad = edad;
  }

  saludar() {
    console.log('Hola, mi nombre es ' + this.nombre);
  }
}

class Estudiante extends Persona {
  constructor(nombre, edad, curso) {
    super(nombre, edad); // Llamada al constructor de Persona
    this.curso = curso;
  }

  estudiar() {
    console.log(this.nombre + ' está estudiando ' + this.curso);
  }
}

const estudiante1 = new Estudiante('Jane', 22, 'Matemáticas');
estudiante1.saludar(); // Hola, mi nombre es Jane
estudiante1.estudiar(); // Jane está estudiando Matemáticas

En este ejemplo, al utilizar class, se define una clase Persona y una clase Estudiante. La palabra clave extends en la definición de Estudiante indica que esta clase hereda de Persona.

super

La palabra clave super en JavaScript se utiliza para acceder o invocar alguno de los métodos o atributos del prototipo o de la clase padre. Por ejemplo, super se usa para llamar al constructor de la clase padre. En el ejemplo anterior, dentro del constructor de la clase Estudiante, se llama al constructor de Persona utilizando super(nombre, edad).

super también se puede utilizar para llamar a métodos de la clase padre dentro de un método de la clase derivada:

class Persona {
  // ...
  
  presentar() {
    return 'Mi nombre es ' + this.nombre + ' y tengo ' + this.edad + ' años.';
  }
}

class Estudiante extends Persona {
  // ...
  
  presentar() {
    const presentacion = super.presentar();
    return presentacion + ' Estoy estudiando ' + this.curso + '.';
  }
}

const estudiante1 = new Estudiante('Jane', 22, 'Matemáticas');
console.log(estudiante1.presentar()); // Mi nombre es Jane y tengo 22 años. Estoy estudiando Matemáticas.

En este ejemplo, se redefine el método presentar en la clase Estudiante y se utiliza super.presentar() para invocar el método presentar de la clase Persona y obtener la cadena de presentación básica y, luego, agregar información adicional relacionada con el curso.

En resumen, la herencia en JavaScript se basa en prototipos y la cadena de prototipos, y puede simplificarse mediante las palabras clave extends y super. Los objetos heredan propiedades y métodos de sus prototipos, lo que permite compartir comportamientos y estructuras entre diferentes objetos. Aunque la herencia en JavaScript es diferente a la herencia basada en clases de otros lenguajes, sigue siendo un enfoque poderoso y flexible para la reutilización de código y la organización de aplicaciones.

Certifícate en JavaScript con CertiDevs PLUS

Ejercicios de esta lección Herencia

Evalúa tus conocimientos de esta lección Herencia con nuestros retos de programación de tipo Test, Puzzle, Código y Proyecto con VSCode, guiados por IA.

Funciones flecha

JavaScript
Puzzle

Polimorfismo

JavaScript
Test

Array

JavaScript
Código

Transformación con map()

JavaScript
Test

Introducción a JavaScript

JavaScript
Test

Gestor de tareas con JavaScript

JavaScript
Proyecto

Manipulación DOM

JavaScript
Test

Funciones

JavaScript
Test

Funciones flecha

JavaScript
Código

Async / Await

JavaScript
Código

Creación y uso de variables

JavaScript
Test

Excepciones

JavaScript
Puzzle

Promises

JavaScript
Código

Funciones cierre (closure)

JavaScript
Test

Herencia

JavaScript
Puzzle

Herencia

JavaScript
Test

Estructuras de control

JavaScript
Código

Selección de elementos DOM

JavaScript
Test

Modificación de elementos DOM

JavaScript
Test

Filtrado con filter() y find()

JavaScript
Test

Funciones cierre (closure)

JavaScript
Puzzle

Funciones

JavaScript
Puzzle

Mapas con Map

JavaScript
Test

Reducción con reduce()

JavaScript
Test

Callbacks

JavaScript
Puzzle

Manipulación DOM

JavaScript
Puzzle

Promises

JavaScript
Test

Async / Await

JavaScript
Test

Eventos del DOM

JavaScript
Puzzle

Async / Await

JavaScript
Puzzle

Promises

JavaScript
Puzzle

Filtrado con filter() y find()

JavaScript
Código

Callbacks

JavaScript
Test

Creación de clases y objetos Restaurante

JavaScript
Código

Reducción con reduce()

JavaScript
Código

Filtrado con filter() y find()

JavaScript
Puzzle

Reducción con reduce()

JavaScript
Puzzle

Conjuntos con Set

JavaScript
Puzzle

Herencia de clases

JavaScript
Código

Eventos del DOM

JavaScript
Test

Clases y objetos

JavaScript
Puzzle

Modificación de elementos DOM

JavaScript
Puzzle

Mapas con Map

JavaScript
Puzzle

Funciones

JavaScript
Código

Tipos de datos

JavaScript
Test

Clases y objetos

JavaScript
Test

Array

JavaScript
Test

Conjuntos con Set

JavaScript
Test

Array

JavaScript
Puzzle

Encapsulación

JavaScript
Puzzle

Clases y objetos

JavaScript
Código

Uso de operadores

JavaScript
Puzzle

Uso de operadores

JavaScript
Test

Estructuras de control

JavaScript
Test

Excepciones

JavaScript
Test

Transformación con map()

JavaScript
Puzzle

Funciones flecha

JavaScript
Test

Selección de elementos DOM

JavaScript
Puzzle

Encapsulación

JavaScript
Test

Mapas con Map

JavaScript
Código

Creación y uso de variables

JavaScript
Puzzle

Polimorfismo

JavaScript
Puzzle

Tipos de datos

JavaScript
Puzzle

Estructuras de control

JavaScript
Puzzle

Todas las lecciones de JavaScript

Accede a todas las lecciones de JavaScript y aprende con ejemplos prácticos de código y ejercicios de programación con IDE web sin instalar nada.

Certificados de superación de JavaScript

Supera todos los ejercicios de programación del curso de JavaScript y obtén certificados de superación para mejorar tu currículum y tu empleabilidad.

En esta lección

Objetivos de aprendizaje de esta lección

  1. Comprender el concepto de herencia en JavaScript y cómo se basa en prototipos.
  2. Conocer el uso de la propiedad [[Prototype]] o __proto__ para establecer la cadena de prototipos.
  3. Aprender cómo crear objetos y funciones constructoras para establecer relaciones de herencia.
  4. Entender cómo la herencia de atributos y métodos funciona a través de la cadena de prototipos.
  5. Aprender a utilizar la función Object.create() para crear objetos con un prototipo específico.
  6. Conocer el uso de las palabras clave extends y super en las clases de ES6 para simplificar la herencia.
  7. Entender cómo agregar o sobrescribir métodos en la cadena de prototipos para personalizar el comportamiento de objetos heredados.
  8. Saber cómo la herencia permite reutilizar código y compartir comportamientos y estructuras entre objetos en JavaScript.