JavaScript
Tutorial JavaScript: Herencia
JavaScript herencia: clases y ejemplos claros. Aprende a implementar herencia en clases de JavaScript con ejemplos claros y detallados.
Aprende JavaScript y certifícateFundamentos de la herencia en JavaScript: Prototipos vs. clases y el sistema de cadena de prototipos
JavaScript implementa la herencia de una manera única entre los lenguajes de programación populares. A diferencia de lenguajes como Java o C++ que utilizan un sistema de clases tradicional, JavaScript se basa fundamentalmente en prototipos para implementar la herencia, incluso cuando utilizamos la sintaxis moderna de clases introducida en ES6.
El sistema basado en prototipos
En JavaScript, cada objeto está vinculado a otro objeto llamado su prototipo. Cuando intentamos acceder a una propiedad o método que no existe en un objeto, JavaScript automáticamente busca en su prototipo, y si no lo encuentra allí, continúa buscando en el prototipo del prototipo, formando lo que se conoce como cadena de prototipos.
Esta búsqueda continúa hasta llegar al final de la cadena, que normalmente es Object.prototype
, cuyo prototipo es null
:
// Creación de un objeto usando la notación literal
const animal = {
estaVivo: true,
comer() {
return "Comiendo...";
}
};
// Creación de un objeto que hereda de animal
const perro = Object.create(animal);
perro.ladrar = function() {
return "Guau!";
};
console.log(perro.estaVivo); // true (heredado de animal)
console.log(perro.comer()); // "Comiendo..." (heredado de animal)
console.log(perro.ladrar()); // "Guau!" (propio de perro)
En este ejemplo, perro
hereda propiedades y métodos de animal
a través de la cadena de prototipos. Cuando accedemos a perro.estaVivo
, JavaScript no encuentra esta propiedad en perro
, por lo que busca en su prototipo (animal
) y la encuentra allí.
Accediendo a los prototipos
Podemos acceder y manipular el prototipo de un objeto de varias formas:
- Object.getPrototypeOf(): Método recomendado para obtener el prototipo de un objeto.
- Object.setPrototypeOf(): Permite cambiar el prototipo de un objeto existente (no recomendado por razones de rendimiento).
- proto: Propiedad de acceso obsoleta pero ampliamente soportada.
// Verificando la cadena de prototipos
console.log(Object.getPrototypeOf(perro) === animal); // true
console.log(Object.getPrototypeOf(animal) === Object.prototype); // true
console.log(Object.getPrototypeOf(Object.prototype) === null); // true
Funciones constructoras y prototipos
Antes de ES6, la forma estándar de implementar herencia era mediante funciones constructoras y la propiedad prototype
:
// Función constructora
function Animal(nombre) {
this.nombre = nombre;
}
// Añadir métodos al prototipo
Animal.prototype.comer = function() {
return `${this.nombre} está comiendo`;
};
// Función constructora que hereda de Animal
function Perro(nombre, raza) {
// Llamar al constructor padre
Animal.call(this, nombre);
this.raza = raza;
}
// Establecer la herencia
Perro.prototype = Object.create(Animal.prototype);
// Restaurar el constructor
Perro.prototype.constructor = Perro;
// Añadir métodos específicos
Perro.prototype.ladrar = function() {
return `${this.nombre} dice: Guau!`;
};
const miPerro = new Perro("Rex", "Pastor Alemán");
console.log(miPerro.nombre); // "Rex"
console.log(miPerro.comer()); // "Rex está comiendo"
console.log(miPerro.ladrar()); // "Rex dice: Guau!"
En este ejemplo, Perro
hereda de Animal
mediante la manipulación de la propiedad prototype
. Cuando creamos una instancia con new Perro()
, el objeto resultante tiene acceso a los métodos definidos en Perro.prototype
y, a través de la cadena de prototipos, a los métodos definidos en Animal.prototype
.
Clases en ES6: Azúcar sintáctico
Con ES6, JavaScript introdujo la sintaxis de clases, que proporciona una forma más clara y familiar de implementar la herencia orientada a objetos. Sin embargo, es importante entender que esto es principalmente azúcar sintáctico sobre el sistema de prototipos existente:
// Definición de clase base
class Animal {
constructor(nombre) {
this.nombre = nombre;
}
comer() {
return `${this.nombre} está comiendo`;
}
}
// Clase que extiende de Animal
class Perro extends Animal {
constructor(nombre, raza) {
super(nombre); // Llama al constructor de Animal
this.raza = raza;
}
ladrar() {
return `${this.nombre} dice: Guau!`;
}
}
const miPerro = new Perro("Rex", "Pastor Alemán");
console.log(miPerro.comer()); // "Rex está comiendo"
console.log(miPerro.ladrar()); // "Rex dice: Guau!"
Bajo el capó, JavaScript sigue utilizando prototipos. La palabra clave extends
configura la cadena de prototipos automáticamente, y super()
llama al constructor de la clase padre.
Diferencias clave entre prototipos y clases
Aunque las clases de ES6 se basan en prototipos, existen algunas diferencias importantes:
- Hoisting: Las clases no se elevan (hoist), mientras que las funciones constructoras sí.
- Modo estricto: El código dentro de las clases se ejecuta automáticamente en modo estricto.
- Métodos: Los métodos definidos en clases no son enumerables por defecto.
- Constructor: Las clases requieren el uso de
new
, mientras que las funciones constructoras pueden llamarse sinnew
(aunque no es recomendable).
// Esto funciona con funciones constructoras
const animal1 = Animal("Simba");
// Esto lanzaría un error: las clases deben llamarse con new
// const animal2 = Animal("Simba");
// Correcto
const animal3 = new Animal("Simba");
Verificación de la cadena de prototipos
JavaScript proporciona métodos para verificar las relaciones de herencia:
const miPerro = new Perro("Rex", "Pastor Alemán");
// Verificar si un objeto es instancia de una clase
console.log(miPerro instanceof Perro); // true
console.log(miPerro instanceof Animal); // true
console.log(miPerro instanceof Object); // true
// Verificar si una propiedad pertenece directamente al objeto
console.log(miPerro.hasOwnProperty("nombre")); // true
console.log(miPerro.hasOwnProperty("comer")); // false (está en el prototipo)
Ventajas del sistema de prototipos
El sistema de prototipos de JavaScript ofrece algunas ventajas interesantes:
- Flexibilidad: Permite modificar el comportamiento de objetos existentes en tiempo de ejecución.
- Memoria eficiente: Los métodos se definen una vez en el prototipo y son compartidos por todas las instancias.
- Herencia dinámica: La cadena de prototipos puede modificarse después de la creación del objeto.
// Extender el prototipo de objetos nativos (no recomendado en código de producción)
String.prototype.saludar = function() {
return `¡Hola, ${this}!`;
};
console.log("mundo".saludar()); // "¡Hola, mundo!"
El sistema de prototipos de JavaScript proporciona una base poderosa y flexible para la herencia, mientras que la sintaxis de clases moderna ofrece una interfaz más limpia y familiar para los desarrolladores que provienen de otros lenguajes orientados a objetos. Comprender ambos enfoques y cómo se relacionan es fundamental para dominar la programación orientada a objetos en JavaScript.
Implementación práctica de jerarquías de herencia: Extensión de clases, super() y polimorfismo
Una vez comprendidos los fundamentos de la herencia basada en prototipos, es momento de explorar cómo implementar jerarquías de herencia efectivas en JavaScript moderno. La sintaxis de clases introducida en ES6 facilita enormemente la creación de estructuras de herencia claras y mantenibles.
Extensión de clases con extends
La palabra clave extends
nos permite crear una clase hija que hereda propiedades y métodos de una clase padre:
class Vehicle {
constructor(make, model, year) {
this.make = make;
this.model = model;
this.year = year;
this.isRunning = false;
}
start() {
this.isRunning = true;
return `The ${this.make} ${this.model} is now running`;
}
stop() {
this.isRunning = false;
return `The ${this.make} ${this.model} has stopped`;
}
getInfo() {
return `${this.year} ${this.make} ${this.model}`;
}
}
class Car extends Vehicle {
constructor(make, model, year, doors) {
super(make, model, year);
this.doors = doors;
this.type = "car";
}
honk() {
return "Beep beep!";
}
}
En este ejemplo, Car
extiende de Vehicle
, heredando todas sus propiedades y métodos. Además, añade sus propias características específicas como el método honk()
y la propiedad doors
.
El papel crucial de super()
La palabra clave super
tiene dos usos fundamentales en la herencia:
- Llamar al constructor padre:
super()
en el constructor - Acceder a métodos del padre:
super.nombreMetodo()
en cualquier método
class ElectricCar extends Car {
constructor(make, model, year, doors, batteryCapacity) {
// Llamada al constructor de la clase padre
super(make, model, year, doors);
this.batteryCapacity = batteryCapacity;
this.fuelType = "electricity";
}
// Sobrescribir un método del padre
start() {
// Llamar a la implementación del padre
const message = super.start();
return `${message} silently`;
}
charge() {
return `Charging the ${this.make} ${this.model}'s ${this.batteryCapacity}kWh battery`;
}
}
const tesla = new ElectricCar("Tesla", "Model 3", 2023, 4, 75);
console.log(tesla.start()); // "The Tesla Model 3 is now running silently"
console.log(tesla.charge()); // "Charging the Tesla Model 3's 75kWh battery"
Es obligatorio llamar a super()
antes de usar this
en el constructor de una clase hija. Esto inicializa correctamente la instancia con las propiedades definidas en la clase padre.
Errores comunes con super()
class Motorcycle extends Vehicle {
constructor(make, model, year, engineSize) {
// Error: No se puede usar 'this' antes de llamar a super()
this.engineSize = engineSize;
super(make, model, year);
}
}
// Correcto:
class Motorcycle extends Vehicle {
constructor(make, model, year, engineSize) {
super(make, model, year);
this.engineSize = engineSize;
}
}
Implementando polimorfismo
El polimorfismo permite que objetos de diferentes clases respondan al mismo método de manera distinta. En JavaScript, esto se logra principalmente sobrescribiendo métodos de la clase padre:
class Vehicle {
constructor(make, model) {
this.make = make;
this.model = model;
}
getDescription() {
return `Vehicle: ${this.make} ${this.model}`;
}
getFuelEfficiency() {
return "Varies by vehicle type";
}
}
class Car extends Vehicle {
getDescription() {
return `Car: ${this.make} ${this.model}, 4 wheels`;
}
getFuelEfficiency() {
return "Average 25 MPG";
}
}
class Motorcycle extends Vehicle {
getDescription() {
return `Motorcycle: ${this.make} ${this.model}, 2 wheels`;
}
getFuelEfficiency() {
return "Average 50 MPG";
}
}
// Demostración de polimorfismo
function describeVehicle(vehicle) {
// El mismo método se comporta diferente según el tipo de objeto
console.log(vehicle.getDescription());
console.log(`Fuel efficiency: ${vehicle.getFuelEfficiency()}`);
}
const car = new Car("Toyota", "Corolla");
const motorcycle = new Motorcycle("Honda", "CBR");
describeVehicle(car);
// Car: Toyota Corolla, 4 wheels
// Fuel efficiency: Average 25 MPG
describeVehicle(motorcycle);
// Motorcycle: Honda CBR, 2 wheels
// Fuel efficiency: Average 50 MPG
En este ejemplo, la función describeVehicle()
trabaja con cualquier objeto que herede de Vehicle
, demostrando el principio de sustitución de Liskov: los objetos de una clase derivada deben poder sustituir a los objetos de la clase base sin afectar la funcionalidad del programa.
Verificación de tipos en jerarquías de herencia
Para trabajar eficazmente con jerarquías de clases, es útil poder verificar el tipo de un objeto:
const vehicle = new Vehicle("Generic", "Vehicle");
const car = new Car("Honda", "Civic", 2022, 4);
const electricCar = new ElectricCar("Tesla", "Model S", 2023, 4, 100);
// Verificación de instancias
console.log(car instanceof Car); // true
console.log(car instanceof Vehicle); // true
console.log(car instanceof ElectricCar); // false
console.log(electricCar instanceof ElectricCar); // true
console.log(electricCar instanceof Car); // true
console.log(electricCar instanceof Vehicle); // true
// Verificar la clase directa
console.log(car.constructor === Car); // true
console.log(electricCar.constructor === ElectricCar); // true
Herencia multinivel
JavaScript permite crear jerarquías de herencia multinivel, donde una clase hereda de otra que a su vez hereda de una tercera:
class SportsCar extends Car {
constructor(make, model, year, doors, topSpeed) {
super(make, model, year, doors);
this.topSpeed = topSpeed;
this.type = "sports";
}
race() {
return `Racing at ${this.topSpeed} mph!`;
}
}
const porsche = new SportsCar("Porsche", "911", 2023, 2, 190);
console.log(porsche.getInfo()); // "2023 Porsche 911"
console.log(porsche.start()); // "The Porsche 911 is now running"
console.log(porsche.honk()); // "Beep beep!"
console.log(porsche.race()); // "Racing at 190 mph!"
En este ejemplo, SportsCar
hereda de Car
, que a su vez hereda de Vehicle
, formando una cadena de herencia de tres niveles.
Propiedades y métodos estáticos en la herencia
Las propiedades y métodos estáticos también se heredan:
class Vehicle {
constructor(make, model) {
this.make = make;
this.model = model;
}
static getVehicleTypes() {
return ["Car", "Truck", "Motorcycle", "Boat"];
}
static isVehicle(obj) {
return obj instanceof Vehicle;
}
}
class Car extends Vehicle {
static getCarTypes() {
return ["Sedan", "SUV", "Hatchback", "Convertible"];
}
}
console.log(Vehicle.getVehicleTypes()); // ["Car", "Truck", "Motorcycle", "Boat"]
console.log(Car.getVehicleTypes()); // ["Car", "Truck", "Motorcycle", "Boat"]
console.log(Car.getCarTypes()); // ["Sedan", "SUV", "Hatchback", "Convertible"]
Limitaciones de la herencia en JavaScript
Aunque la sintaxis de clases facilita la implementación de herencia, JavaScript mantiene algunas limitaciones:
- No hay herencia múltiple: Una clase solo puede extender de una única clase padre.
- No hay interfaces: JavaScript no tiene un sistema de interfaces como Java o TypeScript.
- No hay modificadores de acceso nativos: Aunque existen campos privados con
#
, no hay un sistema completo de visibilidad comoprotected
opackage-private
.
// Esto NO es posible en JavaScript:
// class HybridVehicle extends Car, Boat { ... }
// Alternativa: usar composición
class HybridVehicle {
constructor(make, model, year) {
this.car = new Car(make, model, year, 4);
this.boat = new Boat(make, model, year);
}
driveOnLand() {
return this.car.start();
}
navigateWater() {
return this.boat.sail();
}
}
La implementación práctica de jerarquías de herencia en JavaScript moderno nos permite crear estructuras de código organizadas y reutilizables. Aunque el sistema tiene sus limitaciones, la combinación de la sintaxis de clases con el poderoso sistema de prototipos subyacente proporciona herramientas suficientes para modelar relaciones complejas entre objetos de manera efectiva.
Patrones avanzados y mejores prácticas: Composición vs. herencia, mixins y herencia múltiple simulada
Aunque la herencia es una herramienta fundamental en la programación orientada a objetos, existen patrones más avanzados que pueden ofrecer mayor flexibilidad y mantenibilidad en aplicaciones complejas. En esta sección exploraremos alternativas y complementos a la herencia tradicional en JavaScript.
Composición vs. Herencia
La composición es un patrón de diseño que favorece la construcción de objetos complejos combinando objetos más simples, en lugar de heredar funcionalidades. Este enfoque sigue el principio "favorecer la composición sobre la herencia" y ofrece varias ventajas:
// Enfoque de herencia
class Animal {
constructor(name) {
this.name = name;
}
eat() {
return `${this.name} is eating`;
}
sleep() {
return `${this.name} is sleeping`;
}
}
class Bird extends Animal {
fly() {
return `${this.name} is flying`;
}
}
// Enfoque de composición
class Eater {
constructor(name) {
this.name = name;
}
eat() {
return `${this.name} is eating`;
}
}
class Sleeper {
constructor(name) {
this.name = name;
}
sleep() {
return `${this.name} is sleeping`;
}
}
class Flyer {
constructor(name) {
this.name = name;
}
fly() {
return `${this.name} is flying`;
}
}
// Componiendo un pájaro
class BirdWithComposition {
constructor(name) {
this.name = name;
this.eater = new Eater(name);
this.sleeper = new Sleeper(name);
this.flyer = new Flyer(name);
}
eat() {
return this.eater.eat();
}
sleep() {
return this.sleeper.sleep();
}
fly() {
return this.flyer.fly();
}
}
Ventajas de la composición:
- Flexibilidad: Permite cambiar comportamientos en tiempo de ejecución
- Evita el problema del diamante: No hay ambigüedad cuando dos clases padre tienen métodos con el mismo nombre
- Código más modular: Cada comportamiento está encapsulado en su propia clase
- Evita jerarquías profundas: Las jerarquías de herencia profundas pueden volverse difíciles de entender y mantener
Implementando Mixins
Los mixins son una forma de implementar funcionalidad reutilizable sin usar herencia. En JavaScript, podemos implementarlos de varias maneras:
1. Mixins con Object.assign()
// Definiendo mixins como objetos con métodos
const swimMixin = {
swim() {
return `${this.name} is swimming`;
}
};
const flyMixin = {
fly() {
return `${this.name} is flying`;
}
};
// Clase base
class Animal {
constructor(name) {
this.name = name;
}
}
// Aplicando mixins a una clase
class Duck extends Animal {}
Object.assign(Duck.prototype, swimMixin, flyMixin);
// Uso
const donald = new Duck("Donald");
console.log(donald.swim()); // "Donald is swimming"
console.log(donald.fly()); // "Donald is flying"
2. Mixins como funciones de orden superior
// Definiendo mixins como funciones
function Swimming(Base) {
return class extends Base {
swim() {
return `${this.name} is swimming`;
}
};
}
function Flying(Base) {
return class extends Base {
fly() {
return `${this.name} is flying`;
}
};
}
// Clase base
class Animal {
constructor(name) {
this.name = name;
}
}
// Componiendo múltiples mixins
class Duck extends Flying(Swimming(Animal)) {}
const daffy = new Duck("Daffy");
console.log(daffy.swim()); // "Daffy is swimming"
console.log(daffy.fly()); // "Daffy is flying"
Este enfoque utiliza herencia de clases para implementar mixins, pero de una manera más flexible que permite combinar múltiples comportamientos.
Simulando herencia múltiple
JavaScript no soporta herencia múltiple nativa, pero podemos simularla usando mixins o composición:
// Clases base
class Terrestrial {
constructor(name) {
this.name = name;
}
walk() {
return `${this.name} is walking on land`;
}
}
class Aquatic {
constructor(name) {
this.name = name;
}
swim() {
return `${this.name} is swimming in water`;
}
}
// Simulando herencia múltiple con mixins
function AquaticMixin(Base) {
return class extends Base {
swim() {
return `${this.name} is swimming in water`;
}
};
}
class Amphibian extends AquaticMixin(Terrestrial) {
constructor(name) {
super(name);
}
hibernate() {
return `${this.name} is hibernating`;
}
}
const frog = new Amphibian("Kermit");
console.log(frog.walk()); // "Kermit is walking on land"
console.log(frog.swim()); // "Kermit is swimming in water"
Traits y decoradores
Los traits son similares a los mixins pero con algunas diferencias conceptuales. En JavaScript, podemos implementarlos de manera similar:
// Implementando traits
const HasAge = {
getAge() {
return this.age;
},
setAge(age) {
this.age = age;
}
};
const HasName = {
getName() {
return this.name;
},
setName(name) {
this.name = name;
}
};
// Aplicando traits a una clase
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
}
Object.assign(Person.prototype, HasName, HasAge);
const john = new Person("John", 30);
console.log(john.getName()); // "John"
console.log(john.getAge()); // 30
Decoradores de métodos
Los decoradores son una característica experimental en JavaScript que permite modificar clases y métodos. Aunque aún no están completamente estandarizados, podemos implementar un patrón decorador manualmente:
// Función decoradora
function log(target, name, descriptor) {
const original = descriptor.value;
descriptor.value = function(...args) {
console.log(`Calling ${name} with arguments: ${args}`);
const result = original.apply(this, args);
console.log(`Method ${name} returned: ${result}`);
return result;
};
return descriptor;
}
// Aplicando el decorador manualmente
class Calculator {
add(a, b) {
return a + b;
}
}
// Decorando el método add
const descriptor = Object.getOwnPropertyDescriptor(Calculator.prototype, 'add');
const decoratedDescriptor = log(Calculator.prototype, 'add', descriptor);
Object.defineProperty(Calculator.prototype, 'add', decoratedDescriptor);
// Uso
const calc = new Calculator();
calc.add(2, 3);
// Salida:
// Calling add with arguments: 2,3
// Method add returned: 5
Patrones de delegación
La delegación es un patrón donde un objeto delega operaciones a otro objeto. Es una forma de composición que aprovecha el sistema de prototipos de JavaScript:
const taskActions = {
complete() {
this.completed = true;
return `Task "${this.name}" has been completed`;
},
assign(person) {
this.assignee = person;
return `Task "${this.name}" assigned to ${person}`;
}
};
function createTask(name, description) {
return Object.create(taskActions, {
name: { value: name, writable: true },
description: { value: description, writable: true },
completed: { value: false, writable: true },
assignee: { value: null, writable: true },
createdAt: { value: new Date() }
});
}
const task = createTask("Learn JS", "Study advanced JS patterns");
console.log(task.assign("Alice")); // "Task "Learn JS" assigned to Alice"
console.log(task.complete()); // "Task "Learn JS" has been completed"
Mejores prácticas y recomendaciones
Al decidir entre herencia, composición y otros patrones, considera estas recomendaciones:
- Usa herencia para relaciones "es un": Un gato es un animal
- Usa composición para relaciones "tiene un": Un coche tiene un motor
- Mantén las jerarquías de herencia poco profundas: Evita más de 2-3 niveles
- Prefiere interfaces pequeñas: Clases con muchos métodos son difíciles de mantener
- Considera la composición primero: Evalúa si la composición resuelve tu problema antes de usar herencia
- Combina enfoques cuando sea apropiado: Los mejores diseños a menudo utilizan tanto herencia como composición
// Mal diseño: herencia profunda y rígida
class Vehicle {}
class LandVehicle extends Vehicle {}
class Car extends LandVehicle {}
class SportsCar extends Car {}
class Ferrari extends SportsCar {}
// Mejor diseño: composición con herencia limitada
class Vehicle {
constructor(engine, chassis) {
this.engine = engine;
this.chassis = chassis;
}
}
class Engine {
start() { /* ... */ }
stop() { /* ... */ }
}
class SportEngine extends Engine {
turboBoost() { /* ... */ }
}
// Componiendo un coche deportivo
const ferrari = new Vehicle(
new SportEngine(),
new Chassis("carbon fiber")
);
Los patrones avanzados de herencia y composición en JavaScript ofrecen soluciones flexibles para diseñar sistemas complejos. Al comprender las ventajas y desventajas de cada enfoque, puedes seleccionar el patrón más adecuado para cada situación, creando código más mantenible, extensible y robusto.
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
Polimorfismo
Array
Transformación con map()
Gestor de tareas con JavaScript
Manipulación DOM
Funciones
Funciones flecha
Async / Await
Creación y uso de variables
Excepciones
Promises
Funciones cierre (closure)
Herencia
Herencia
Estructuras de control
Selección de elementos DOM
Modificación de elementos DOM
Filtrado con filter() y find()
Funciones cierre (closure)
Funciones
Mapas con Map
Reducción con reduce()
Callbacks
Manipulación DOM
Promises
Async / Await
Eventos del DOM
Async / Await
Promises
Filtrado con filter() y find()
Callbacks
Creación de clases y objetos Restaurante
Reducción con reduce()
Filtrado con filter() y find()
Reducción con reduce()
Conjuntos con Set
Herencia de clases
Eventos del DOM
Clases y objetos
Modificación de elementos DOM
Mapas con Map
Introducción a JavaScript
Funciones
Tipos de datos
Clases y objetos
Array
Conjuntos con Set
Array
Encapsulación
Clases y objetos
Uso de operadores
Uso de operadores
Estructuras de control
Excepciones
Transformación con map()
Funciones flecha
Selección de elementos DOM
Encapsulación
Mapas con Map
Creación y uso de variables
Polimorfismo
Tipos de datos
Estructuras de control
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.
Introducción A Javascript
Introducción Y Entorno
Tipos De Datos
Sintaxis
Variables
Sintaxis
Operadores
Sintaxis
Estructuras De Control
Sintaxis
Funciones
Sintaxis
Funciones Cierre (Closure)
Sintaxis
Arrays Y Métodos
Estructuras De Datos
Conjuntos Con Set
Estructuras De Datos
Mapas Con Map
Estructuras De Datos
Funciones Flecha
Programación Funcional
Filtrado Con Filter() Y Find()
Programación Funcional
Transformación Con Map()
Programación Funcional
Reducción Con Reduce()
Programación Funcional
Clases Y Objetos
Programación Orientada A Objetos
Excepciones
Programación Orientada A Objetos
Encapsulación
Programación Orientada A Objetos
Herencia
Programación Orientada A Objetos
Polimorfismo
Programación Orientada A Objetos
Manipulación Dom
Dom
Selección De Elementos Dom
Dom
Modificación De Elementos Dom
Dom
Eventos Del Dom
Dom
Callbacks
Programación Asíncrona
Promises
Programación Asíncrona
Async / Await
Programación Asíncrona
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
- Comprender el concepto de herencia en JavaScript y cómo se basa en prototipos.
- Conocer el uso de la propiedad
[[Prototype]]
o__proto__
para establecer la cadena de prototipos. - Aprender cómo crear objetos y funciones constructoras para establecer relaciones de herencia.
- Entender cómo la herencia de atributos y métodos funciona a través de la cadena de prototipos.
- Aprender a utilizar la función
Object.create()
para crear objetos con un prototipo específico. - Conocer el uso de las palabras clave
extends
ysuper
en las clases de ES6 para simplificar la herencia. - Entender cómo agregar o sobrescribir métodos en la cadena de prototipos para personalizar el comportamiento de objetos heredados.
- Saber cómo la herencia permite reutilizar código y compartir comportamientos y estructuras entre objetos en JavaScript.