Добавить в корзинуПозвонить
Найти в Дзене
ZDG

Наследование в JavaScript: родительский конструктор

Предыдущие части: Тему про наследование методов можно закрыть. Осталось рассмотреть наследование свойств. Свойства не наследуются, а копируются. Это нормально, так как у каждого объекта должна быть собственная копия свойств. Чтобы было понятнее, повторю: Наследование подразумевает, что у нас чего-то нет, и мы берем это из объекта-родителя. Именно так происходит с методами. Если у нас нет свойства, мы можем взять его из родителя так же как и метод, но на практике это не имеет смысла. Свойства нужны в основном для того, чтобы можно было их менять. А значит, взяв свойство у родителя и изменив его, мы изменим его у родителя – и соответственно у всех его детей, которые будут обращаться к этому свойству. Что в большинстве случаев не нужно. Поэтому обратимся к конструктору объекта, в котором создаются свойства: function A() {
this.a = 1;
} function B() {
this.b = 2;
} Мы хотим отнаследовать класс B от класса A так, чтобы в B появилось свойство a. Для этого из конструктора B нужно вызвать конс

Предыдущие части:

Тему про наследование методов можно закрыть. Осталось рассмотреть наследование свойств.

Свойства не наследуются, а копируются. Это нормально, так как у каждого объекта должна быть собственная копия свойств.

Чтобы было понятнее, повторю:

Наследование подразумевает, что у нас чего-то нет, и мы берем это из объекта-родителя. Именно так происходит с методами. Если у нас нет свойства, мы можем взять его из родителя так же как и метод, но на практике это не имеет смысла.

Свойства нужны в основном для того, чтобы можно было их менять. А значит, взяв свойство у родителя и изменив его, мы изменим его у родителя – и соответственно у всех его детей, которые будут обращаться к этому свойству. Что в большинстве случаев не нужно.

Поэтому обратимся к конструктору объекта, в котором создаются свойства:

function A() {
this.a = 1;
}

function B() {
this.b = 2;
}

Мы хотим отнаследовать класс B от класса A так, чтобы в B появилось свойство a.

Для этого из конструктора B нужно вызвать конструктор A:

function B() {
A.call(this);
this.b = 2;
}

Что происходит:

К конструктору B прикладывается некий новый объект (this), в котором нужно создать свойства. Мы берём этот объект и сначала прикладываем его к конструктору A() с помощью

A.call(this);

В этом объекте создалось свойство a. После этого мы уже в своём конструкторе B() добавляем к this свойство b:

this.b = 2;

И теперь объект содержит свойства a и b. Это его собственные свойства, которые можно менять.

В других языках аналогичный механизм работает через вызов super() или parent.

В общем-то всё, задача решена. Но остался один нюанс: как именно вызывать родительский конструктор. Например, когда мы пишем A(), то создаём явную зависимость от класса A() в нашем коде.

Она не грозит нам ничем, кроме снижения удобства. Скажем, если мы захотим сделать прототипом B другой класс, то придётся вручную исправлять имя A() на другое.

Решить это можно через обращение к прототипу. Как мы ранее видели, у прототипа есть свойство constructor, которое и равно конструктору этого самого прототипа.

function B() {
B.prototype.constructor.call(this);
this.b = 2;
}

Теперь мы можем назначить прототипом для B любой класс, и его имя не надо будет исправлять в конструкторе B().

Приведу финальный пример с наследованием метода и свойства:

Статические свойства

Теперь рассмотрим ситуацию, когда свойства не копируются, а именно наследуются, то есть берутся непосредственно из родителя.

Как правило, такие свойства предназначены только для чтения. Но ничто не мешает их менять. Главное помнить, что меняться они будут в классе-родителе, и значит все его дети будут получать доступ именно к изменённому свойству.

Свойство можно просто создать в прототипе:

-2

Обратите внимание, что конструктор B() больше не вызывает конструктор A(). Через инспектор свойств можно убедиться, что объект obj не имеет свойства a, но тем не менее оно выводится на печать, так как добывается из прототипа.

Можно сделать и чисто статическое свойство, то есть такое, которое по определению не требует создания экземпляра объекта. Его нужно просто добавить к конструктору, например:

A.type = 1;

Далее мы можем, по аналогии с другими языками, обращаться к свойству через имя класса:

var t = A.type;

Правда, нужно помнить, что в других языках классы это классы, а в JS это всегда объекты, так что экземпляр объекта уже по-любому создан и свойство получается не очень-то статическое.

Здесь главное – следовать заданной концепции и не нарушать её, хотя возможностей для нарушений очень много.

Это была последняя часть про наследование в JavaScript.