4.1 Наследование — это просто
Наследование — это фундаментальная концепция объектно-ориентированного программирования (ООП), которая позволяет одному классу (называемому дочерним или подклассом) наследовать поля и методы другого класса (называемого родительским или суперклассом).
Такой подход позволяет создавать более общие классы и повторно использовать код, улучшая организацию и поддерживаемость кода.
Зачем нужно наследование?
Допустим вам нужно написать какой-то код, и вы решили сделать это в виде класса. Потом вы узнали, что в вашем проекте уже существует класс, который делает почти все что нужно и вам в вашем классе. Вы можете просто скопировать код этого класса в свой, и пользоваться в свое удовольствие.
А можете «как бы скопировать». Вы можете объявить тот класс родителем своего класса, и тогда JavaScript добавить вашему классу поведение класса родителя.
Представьте, что вы природа и хотите создать Собаку. Что будет быстрее: создать собаку из бактерии за миллиард лет или одомашнить волка за 200 тысяч?
4.2 Концепция наследования через прототипы
Наследование через прототипы в JavaScript — это один из основных механизмов, который позволяет объектам наследовать свойства и методы других объектов. Это позволяет создавать сложные иерархии объектов и повторно использовать код.
Каждый объект в JavaScript имеет скрытое свойство [[Prototype]], которое указывает на его прототип. Прототипы используются для реализации наследования, что позволяет объектам наследовать свойства и методы от других объектов.
Пример простого наследования
Шаг 1: Создание базового объекта
const animal = {
eat() {
console.log('Eating...');
},
sleep() {
console.log('Sleeping...');
}
};
Шаг 2: Создание объекта-наследника
const dog = Object.create(animal);
dog.bark = function() {
console.log('Barking...');
};
Шаг 3: Использование наследуемых свойств и методов
dog.eat(); // Выведет: Eating...
dog.sleep(); // Выведет: Sleeping...
dog.bark(); // Выведет: Barking...
В этом примере объект dog наследует методы eat() и sleep() от объекта animal и добавляет свой метод — bark().
4.3 Глубокое наследование через прототипы
Цепочка прототипов
В JavaScript наследование может быть более сложным, когда объекты наследуют друг от друга, образуя цепочку прототипов.
Пример цепочки прототипов
В этом примере объект dog наследуется от mammal, который в свою очередь наследуется от animal. Это создает цепочку прототипов, где dog имеет доступ ко всем методам mammal и animal.
const animal = {
eat() {
console.log('Eating...');
}
};
const mammal = Object.create(animal);
mammal.walk = function() {
console.log('Walking...');
};
const dog = Object.create(mammal);
dog.bark = function() {
console.log('Barking...');
};
dog.eat(); // Выведет: Eating...
dog.walk(); // Выведет: Walking...
dog.bark(); // Выведет: Barking...
Проверка цепочки прототипов
Метод isPrototypeOf() позволяет проверить, является ли объект прототипом другого объекта.
Пример:
console.log(animal.isPrototypeOf(mammal)); // Выведет: true
console.log(mammal.isPrototypeOf(dog)); // Выведет: true
console.log(animal.isPrototypeOf(dog)); // Выведет: true
4.4 Переопределение методов
Наследование через прототипы позволяет не только добавлять новые методы, но и переопределять существующие методы.
Пример переопределения методов
В этом примере метод speak() у объекта dog переопределяет метод speak() у объекта animal:
const animal = {
speak() {
console.log('Animal speaks');
}
};
const dog = Object.create(animal);
dog.speak = function() {
console.log('Dog barks');
};
animal.speak(); // Выведет: Animal speaks
dog.speak(); // Выведет: Dog barks
Вызов метода родительского объекта
Для вызова метода родительского объекта в JavaScript можно использовать метод call() или apply().
Пример:
const animal = {
speak() {
console.log('Animal speaks');
}
};
const dog = Object.create(animal);
dog.speak = function() {
animal.speak.call(this);
console.log('Dog barks');
};
dog.speak();
// Выведет:
// Animal speaks
// Dog barks
4.5 Углубленное использование прототипного наследования
Расширение встроенных объектов
Вы можете расширять встроенные объекты JavaScript, добавляя методы в их прототипы.
Пример:
Array.prototype.sum = function() {
return this.reduce((acc, value) => acc + value, 0);
};
const numbers = [1, 2, 3, 4, 5];
console.log(numbers.sum()); // Выведет: 15
Создание многоуровневых иерархий
Вы можете создавать более сложные многоуровневые иерархии объектов с помощью прототипного наследования.
Пример:
const livingBeing = {
breathe() {
console.log('Breathing...');
}
};
const animal = Object.create(livingBeing);
animal.eat = function() {
console.log('Eating...');
};
const mammal = Object.create(animal);
mammal.walk = function() {
console.log('Walking...');
};
const dog = Object.create(mammal);
dog.bark = function() {
console.log('Barking...');
};
dog.breathe(); // Выведет: Breathing...
dog.eat(); // Выведет: Eating...
dog.walk(); // Выведет: Walking...
dog.bark(); // Выведет: Barking...
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
классаобъекта - вот этот пример более наглядный, тот что в тексте на первый взгляд просто усложняет код.