Научете задълбочено за прототипите, прототипната верига и прототипите на 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, което има името constructor. Това име няма нищо общо с класовата система.

Ред 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 от гледна точка на традиционните езици за програмиране.

Прототип Dunder

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

Всеки път, когато има нещо като __something__, то се нарича Дъндър. Следователно __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, тъй като това е сайтът за повикване.