Skip to main content

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

  • В JavaScript все объекты имеют скрытое свойство [[Prototype]], которое является либо другим объектом, либо null.
  • Мы можем использовать obj.__proto__ для доступа к нему (исторически обусловленный геттер/сеттер, есть другие способы, которые скоро будут рассмотрены).
  • Объект, на который ссылается [[Prototype]], называется «прототипом».
  • Если мы хотим прочитать свойство obj или вызвать метод, которого не существует у obj, тогда JavaScript попытается найти его в прототипе.
  • Операции записи/удаления работают непосредственно с объектом, они не используют прототип (если это обычное свойство, а не сеттер).
  • Если мы вызываем obj.method(), а метод при этом взят из прототипа, то this всё равно ссылается на obj. Таким образом, методы всегда работают с текущим объектом, даже если они наследуются.
  • Цикл for..in перебирает как свои, так и унаследованные свойства. Остальные методы получения ключей/значений работают только с собственными свойствами объекта.

Prototype

В JavaScript объекты имеют специальное скрытое свойство [[Prototype]] (так оно названо в спецификации), которое либо равно null, либо ссылается на другой объект.
Когда мы хотим прочитать свойство из object, а оно отсутствует, JavaScript автоматически берёт его из прототипа. В программировании такой механизм называется «прототипным наследованием».

Свойство [[Prototype]] является внутренним и скрытым, но есть много способов задать его.

Одним из них является использование __proto__

💥 Свойство __proto__ — исторически обусловленный геттер/сеттер для [[Prototype]]
Обратите внимание, что proto — не то же самое, что внутреннее свойство [[Prototype]].

Это геттер/сеттер для [[Prototype]]. Позже мы увидим ситуации, когда это имеет значение, а пока давайте просто будем иметь это в виду, поскольку мы строим наше понимание языка JavaScript.

Свойство __proto__ немного устарело, оно существует по историческим причинам. Современный JavaScript предполагает, что мы должны использовать функции Object.getPrototypeOf/Object.setPrototypeOf вместо того, чтобы получать/устанавливать прототип. Мы также рассмотрим эти функции позже.

По спецификации __proto__ должен поддерживаться только браузерами, но по факту все среды, включая серверную, поддерживают его. Так что мы вполне безопасно его используем.

Операция записи не использует прототип

Прототип используется только для чтения свойств.
Операции записи/удаления работают напрямую с объектом.

Значение «this»

Неважно, где находится метод: в объекте или его прототипе. При вызове метода this — всегда объект перед точкой.

Таким образом, вызов сеттера admin.fullName= в качестве this использует admin, а не user.

Цикл for…in

Цикл for..in проходит не только по собственным, но и по унаследованным свойствам объекта.

Если унаследованные свойства нам не нужны, то мы можем отфильтровать их при помощи встроенного метода obj.hasOwnProperty(key): он возвращает true, если у obj есть собственное, не унаследованное, свойство с именем key.

🚀 Источник: https://learn.javascript.ru/prototype-inheritance