Простое наследование в JavaScript: что нужно знать
Многие мои друзья занимаются разработкой программного обеспечения на C# или C++. Они привыкли использовать наследование в своих проектах, и когда они хотят изучить JavaScript, один из первых вопросов, который они задают, звучит так: «А как реализовать наследование на JavaScript?».
И в самом деле, JavaScript использует другой подход, чем C# или C++. JavaScript является прототип-ориентированным языком. Концепция прототипного программирования предполагает, что поведение может быть повторно использовано путем клонирования существующих объектов, выступающих в роли прототипов.
Каждый объект в JavaScript зависит от прототипа, который определяет набор функций и членов, доступных объекту для использования. Нет класса как такового — только объекты. Любой объект может быть использован в качестве прототипа для другого объекта.
Эта концепция является очень гибкой, поэтому может использоваться для реализации некоторых понятий объектно-ориентированного программирования, таких как наследование.
Реализация наследования
Давайте взглянем на иерархию наследования, которую мы создадим, используя JavaScript:

Можно легко создать ClassA. Поскольку нет явных классов, мы можем определить поведенческий набор, просто создав функцию, подобную этой:
var ClassA = function() {
this.name = "class A";
}
Экземпляр этого «класса» может быть создан с помощью ключевого слова new:
var a = new ClassA();
ClassA.prototype.print = function() {
console.log(this.name);
}
Используем его с помощью нашего объекта:
a.print();
Довольно просто, не правда ли?
Весь пример занимает всего восемь строк кода:
var ClassA = function() {
this.name = "class A";
}
ClassA.prototype.print = function() {
console.log(this.name);
}
var a = new ClassA();
a.print();
Теперь давайте добавим инструмент для создания «наследования» между классами. Этот инструмент должен делать всего одну вещь: клонировать прототип:
var inheritsFrom = function (child, parent) {
child.prototype = Object.create(parent.prototype);
};
Именно здесь происходит магия! Клонируя прототип, мы передаем все члены и функции в новый класс.
Таким образом, если мы хотим добавить второй класс, который будет наследником первого, нам нужно просто использовать следующий код:
var ClassB = function() {
this.name = "class B";
this.surname = "I'm the child";
}
inheritsFrom(ClassB, ClassA);
Так как ClassB наследует функцию print от ClassA, следующий код работает:
var b = new ClassB();
b.print();
И создает такой вывод:
class B
Мы даже можем переопределить функцию print для ClassB:
ClassB.prototype.print = function() {
ClassA.prototype.print.call(this);
console.log(this.surname);
}
В данном случае, полученный результат выглядит следующим образом:
class B
I’m the child
Хитрость здесь в том, чтобы вызвать ClassA.prototype для получения базовой функции print. Затем благодаря функции call мы можем вызвать базовую функцию для текущего объекта (this).
Создание ClassC:
var ClassC = function () {
this.name = "class C";
this.surname = "I'm the grandchild";
}
inheritsFrom(ClassC, ClassB);
ClassC.prototype.foo = function() {
// Do some funky stuff here...
}
ClassC.prototype.print = function () {
ClassB.prototype.print.call(this);
console.log("Sounds like this is working!");
}
var c = new ClassC();
c.print();
Результат выполнения кода следующий:
class C
I’m the grandchild
Sounds like this is working!
И немного философии...
В заключение, я хочу объяснить, что JavaScript – это не C# или C++. У него своя философия. Если вы C# или C++ разработчик и действительно хотите ощутить всю силу JavaScript, лучший совет, который я могу вам дать: не пытайтесь применять методики объектно-ориентированного программирования в JavaScript. Не существует лучшего или худшего языка. Есть просто разные философии!