Подробно изучите прототипы, цепочку прототипов и прототипы dunder.

Прежде чем начать понимать, что такое прототипы, вам нужно знать, как работает new ключевое слово. Это связано с тем, что ключевое слово new считается вызовом конструктора, но на самом деле оно служит гораздо более глубокой цели, которая ведет к прототипу, цепочке прототипов, прототипу dunder и ключевому слову this.

Все объекты в нашем коде создаются с помощью «вызова конструктора» (через new). В процессе создания эти объекты создаются «на основе» прототипа их конструктора. Вызов конструктора создает объект на основе собственного прототипа. Часть «на основе» — это 💀 неправильное направление.

То, что это вызов конструктора, не означает, что конструктор существует. Это из-за отсутствия лучшего термина.

Теория классов

Это означает, что классово-ориентированное кодирование по своей сути является операцией копирования. В настоящее время не существует конкретного стандарта того, что на самом деле представляет собой шаблон проектирования классов, но среди программистов преобладают способы Java/C++ (традиционные языки, ориентированные на классы). Это создает ожидание того, как должен работать классово-ориентированный язык, копирование.

Когда вы берете чертеж здания и создаете здание, вернитесь к чертежу и внесите в него изменения. Повлияет ли это на здание, которое вы только что создали?

Нет, потому что связь между классом и экземпляром существовала «долю секунды», характеристики класса были скопированы, после чего связь перестает существовать. Наследование по своей сути также является операцией копирования.

Поэтому, когда мы говорим — «вызов конструктора» создает объект «на основе» его собственного прототипа, мы говорим, что конструктор создает копию прототипа в экземпляре. За исключением того, что JavaScript вообще не копирует. Это не «основано на», это на самом деле «связано с».

«Вызов конструктора» связывает объект со своим собственным прототипом.

Связывание и копирование — принципиально разные операции. Из-за этого принципиально другого способа работы, т. е. связывания, JavaScript ведет себя не так, как языки программирования, такие как Java/C++.

Прототип класса

Традиционный способ создания «классов» в JavaScript. Это называется прототипным классом.

function Comment(author) {
  this.author = author;
}

Comment.prototype.makeComment = function (message) {
  console.log(this.author + " - " + message);
};

var comment1 = new Comment("James");
var comment2 = new Comment("Bond");

comment1.makeComment("I love this!");
// James - I love this!

comment2.makeComment("What's this?");
// Bond - What's this?

Это то, что делает для нас ключевое слово class, и это то, что мы в основном используем в современном JavaScript. Поскольку это не операция копирования, важно знать, как работают классы и где находятся все связи.

Сеть прототипов

Мы рассмотрим следующий пример кода, чтобы понять цепочку прототипов. Кроме того, чтобы понять, мы будем использовать диаграммы, где:

  • ⬛️ квадраты представляют объекты
  • ⚫️ кружки обозначают функции

Строка 0

Еще до того, как наш код запустится, у нас есть функция с именем Object. Это один из фундаментальных и наиболее важных объектов в JavaScript. Он также имеет несколько утилит, таких как Object.values &Object.keys. Таким образом, он также служит пространством имен для других методов.

Здесь также существует объект, самый важный объект во всем JavaScript. У нас нет для него имени, поэтому он назван в соответствии с тем, что на него указывает. Свойство Object, указывающее на эту вещь, называется прототип, поэтому мы называем этот важный объект Object.prototype.

В этом Object.prototype есть некоторые важные вещи, такие как toString, valueOf и все эти другие фундаментальные утилиты, которые существуют в JavaScript.

Все непримитивы происходят непосредственно от этого Object.prototype

Также есть еще одно свойство, указывающее на Object с именем конструктор. Это имя не имеет ничего общего с системой классов.

Линия 1

Здесь у нас есть функция Comment, а также объект, созданный благодаря функции Comment. На данный момент он пуст, но позже он будет служить важной цели. Мы ссылаемся на этот объект как Comment.prototype. Кроме того, есть свойство, указывающее назад, и оно называется конструктором.

Существует скрытая связь между объектом, «созданным функцией Comment» и «объектом, созданным функцией Object». Мы обсудим это в статье.

Строка 5

Здесь мы добавили свойство info (неважно, функция это или нет) в файл Comment.prototype.

Переход к строке 9.

Строка 9

Здесь мы используем ключевое слово new для вызова функции Comment. Когда мы используем ключевое слово new, происходят 4 вещи:

  • Он создает пустой объект
  • затем он связывает этот объект с другим объектом
  • Затем функция (в данном случае Comment) с this указывает на объект, созданный ключевым словом new
  • Наконец, если функция ничего не возвращает, ключевое слово new возвращает только что созданный объект.

Прочтите статью о ключевом слове new, чтобы подробно узнать о его работе.

Итак, в этом случае ключевое слово new создало объект и связало его с Workshop.prototype. Затем он вызывает функцию Comment, где this указывает на вновь созданный объект, а teacher добавляется к этому новому объекту со значением I love this! (это происходит в строке 2).

Аналогично в этом случае со строкой 10.

Строка 12

Здесь, когда мы запускаем makeComment для объекта comment1, мы не получаем ошибки, хотя comment1 не имеет свойства makeComment. Почему? Поскольку теперь существует внутренняя скрытая связь, называемая цепочкой прототипов, между comment1 и Workshop.prototype, всякий раз, когда мы ищем свойство, а оно не существует, по умолчанию JavaScript перемещается на один уровень вверх в этой цепочке прототипов к посмотрите, есть ли он у этого объекта ИЛИ нет.

В этом случае мы перейдем от comment1 к Workshop.prototype и проверим наличие makeComment. Поскольку он там существует, мы можем использовать makeComment на объекте comment1. Здесь this внутри функции makeComment указывает на объект comment1, потому что контекст для this зависит от его реального места вызова, которым здесь является строка 12.

Прочитайте статью о this ключевом слове, чтобы узнать больше о его работе.

Заключение

Мы можем совместно использовать один метод info с несколькими экземплярами, и все они могут совместно использовать его из-за this поведения привязки и связи с прототипом. Именно это делает прототипы в JavaScript очень мощными. По этой причине не рассматривайте JavaScript с точки зрения традиционных языков программирования.

Дандер Прототип

Функция Comment не имеет ничего общего с созданием comment1. Именно ключевое слово new создало объект comment1. Когда вы сделаете comment1.constructor == Comment, вы получите true. Это просто для того, чтобы сказать, что Comment был создан comment1 (что не соответствует действительности).

Всякий раз, когда есть что-то вроде __something__, это называется Dunder. Поэтому __proto__ называется dunder proto, а comment1.__proto__ будет называться 🗣 «comment 1 dunder proto».

function Comment(author) {
  this.author = author;
}

Comment.prototype.makeComment = function (message) {
  console.log(this.author + " - " + message);
};

var comment1 = new Comment("James");

// Prototype Linkage/Chain
console.log(comment1.constructor === Comment); // true
console.log(comment1.__proto__ === Comment.prototype); // true
console.log(Object.getPrototypeOf(comment1) === Comment.prototype); // true

Что такое (comment1.__proto__ == Comment.prototype) = true? Это означает, что __proto__ в объекте относится к объекту, с которым он связан в цепочке прототипов.

Здесь comment1 не имеет такого свойства, как __proto__, поэтому мы поднимаемся на один уровень вверх по цепочке прототипов к Comment.prototype. Comment.prototype также не имеет __proto__. Итак, теперь мы поднимаемся на один уровень вверх по цепочке прототипов, снова к Object.prototype.

В Object.prototype у нас есть __proto__, это не свойство, а функция получения/установки. comment1.__proto__ обращается к нему как к свойству, но когда к нему обращаются, вызывается функция, и ключевое слово this в нем будет указывать на объект comment1, так как это место вызова.