Это обновление из другого моего поста, и, как оказалось, оно немного вводило в заблуждение.

Для тех, кто сразу попал на этот пост, вот что я собираюсь сделать: представить концепции наследования с помощью JavaScript словами, которые я использовал, чтобы понять их сам.

Для начала представим один из самых часто задаваемых вопросов на фронтенд-интервью,

В чем разница между классическим и прототипным наследованием в JS?

или это альтер-эго,

Как вы реализуете классическое наследование и прототипное наследование в JS?

или иногда более общий,

Расскажите о наследовании в JavaScript

Теперь есть несколько способов достижения наследования с помощью JavaScript, и они были разделены на две школы:

  1. Классический
  2. Прототип

Начнем с классического наследования.

Как следует из названия, это связано с классами или чертежами.

Java-способ сделать это будет примерно таким:
https://gist.github.com/rohanBagchi/f48e13f8bcbb059602f92a149ec015a4

Так вот, JavaScript из-за времени его изобретения должен был выглядеть как Java.

Для отношения Employee и Accountant это можно сделать в JavaScript, который имитирует поведение классов.

Employee и Accountant — это карты или чертежи, которые определяют, как должен выглядеть результирующий объект.

Это создает тесную связь между родителем и дочерним элементом, в нашем случае Employee и Accountant.

Эта строка:

Accountant.prototype = Object.create(Employee.prototype);

Он был добавлен для того, чтобы JS работал с магией, основанной на прототипах.

Видите ли, мы добавили новый метод в прототип Employee после определения Accountant.

Employee.prototype.sayName = function() {
    return `My name is ${this.name}`;
};

Из-за нашего сопоставления прототипа Accountant с прототипом Employee мы теперь можем получить доступ к методам, определенным в родительском объекте.

Это классическое или классовое наследование в JavaScript.

Переходим к прототипному наследованию

Этот, как следует из названия, имеет какое-то отношение к прототипам или экземплярам объектов.

Их можно условно разделить на 2 типа:

  1. Конкатенация (с фабричными функциями)
  2. Прототип делегирования

Concatenative проще всего рассуждать, и любой, кто работает с react/redux, использовал бы его изо дня в день.

Все сводится к использованию restspread ES6 или Object.assign.

const Employee = {
    name: 'John Doe'
};
const Accountant = {
    ...Employee,
    role: 'accountant'
};

Этот шаблон становится более удобным, когда фабричные функции возвращают объекты:

const getEmployee = name => ({
    name
});
const getAccountant = name => ({
    ...getEmployee(name),
    role: 'Accountant'
});

Делегирование прототипа связано со свойством __proto__ всех объектов JS.

По сути, это работает как неявная ссылка на другой объект.

const Employee = {
    name: 'John Doe'
};
const Accountant = {
    role: 'accountant'
};
Accountant.__proto__ = Employee;

И это все, что нужно для понимания наследования.

Спасибо за чтение.

Найдите меня на linkedin или в твиттере @rohanBagchi или вернитесь ко мне в комментариях.

Меня зовут Рохан. Я пишу о технологиях, в основном о JavaScript: React, Redux, реактивные истории производительности приложений и инженерия интерфейса.