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