Прототипическое наследование в JavaScript

В объектно-ориентированном программировании наследование — это механизм, позволяющий одному объекту приобретать свойства и поведение другого объекта. В JavaScript нет традиционного наследования на основе классов, как во многих других языках. Вместо этого он использует прототипное наследование. Эта концепция может показаться немного сложной для разработчиков, использующих языки, основанные на классах, но это одна из уникальных особенностей, которые выделяют JavaScript.

Цепочка прототипов

У каждого объекта в JavaScript есть прототип, кроме базового объекта. Когда вы пытаетесь получить доступ к свойству или методу объекта, JavaScript сначала проверяет сам объект. Если он его там не находит, он будет искать прототип объекта, затем прототип прототипа и так далее, пока не найдет свойство/метод или не достигнет объекта с нулевым прототипом.

Понимание прототипа

Когда вы создаете объект с помощью функции-конструктора, построенный объект наследует свойства и методы из ConstructorFunction.prototype.

Например:

function Dog(name) {
 this.name = name;
}
Dog.prototype.bark = function() {
 console.log(this.name + ' barks!');
};
const dog1 = new Dog('Rex');
dog1.bark(); // Outputs: Rex barks!

Здесь `dog1` не имеет собственного метода `bark`. Но у него есть доступ к `bark`, потому что он доступен на `Dog.prototype`.

Объект.создать()

Другой способ установить прототипное наследование — использовать `Object.create()`. Этот метод создает новый объект с указанным объектом-прототипом.

const animal = {
 makeSound: function() {
 console.log('Some sound');
 }
};
const dog = Object.create(animal);
dog.makeSound(); // Outputs: Some sound

В приведенном выше коде `dog` — это объект, наследуемый от `animal`.

Прототипическое наследование в действии

Предположим, вы хотите создать `Cat`, наследуемый от `Animal`:

function Animal(voice) {
 this.voice = voice || 'grunt';
}
Animal.prototype.speak = function() {
 console.log(this.voice);
};
function Cat(name, color) {
 Animal.call(this, 'Meow'); // Call the super constructor.
 this.name = name;
 this.color = color;
}
// Setting up the prototype chain
Cat.prototype = Object.create(Animal.prototype);
Cat.prototype.constructor = Cat;
Cat.prototype.details = function() {
 console.log(this.name + ' is ' + this.color);
};
const cat1 = new Cat('Misty', 'white');
cat1.speak(); // Outputs: Meow
cat1.details(); // Outputs: Misty is white

В этом примере:
1. `Cat` вызывает конструктор `Animal`, наследуя его свойства.
2. Мы устанавливаем `Cat.prototype` объекту, который наследуется от `Animal.prototype` с помощью `Object.create()`.
3. Мы переназначаем `Cat.prototype.constructor` на `Cat`. , поскольку использование `Object.create()` переопределило бы исходное свойство конструктора.
4. `cat1` может получить доступ как к `speak` из `Animal.prototype`, так и к `details` из `Cat.prototype`.

Подведение итогов

Прототипическое наследование — уникальная и мощная функция JavaScript. Он обеспечивает гибкость при расширении объектов и создании новых типов. Хотя это может быть незнакомо разработчикам, привыкшим к наследованию на основе классов, понимание цепочки прототипов имеет решающее значение для освоения JavaScript.