Nie przepadam za dynamicznymi językami programowania, ale napisałem sporo kodu JavaScript. Nigdy tak naprawdę nie zastanawiałem się nad tym programowaniem opartym na prototypach, czy ktoś wie, jak to działa?
var obj = new Object();
obj.prototype.test = function() { alert('Hello?'); };
var obj2 = new obj();
obj2.test();
Pamiętam wiele dyskusji, które miałem z ludźmi jakiś czas temu (nie jestem do końca pewien, co robię), ale rozumiem, że nie ma pojęcia o klasie. To tylko przedmiot, a instancje tych obiektów są klonami oryginału, prawda?
Ale jaki jest dokładnie cel tej właściwości „.prototype” w JavaScript? Jaki to ma związek z tworzeniem obiektów?
Aktualizacja: poprawny sposób
var obj = new Object(); // not a functional object
obj.prototype.test = function() { alert('Hello?'); }; // this is wrong!
function MyObject() {} // a first class functional object
MyObject.prototype.test = function() { alert('OK'); } // OK
Te slajdy naprawdę bardzo pomogły.
javascript
dynamic-languages
prototype-oriented
John Leidegren
źródło
źródło
Odpowiedzi:
Każdy obiekt JavaScript posiada wewnętrzny „gniazdo” o nazwie
[[Prototype]]
, której wartość jest albonull
alboobject
. Możesz myśleć o gnieździe jako o właściwości obiektu, wewnętrznej w silniku JavaScript, ukrytej przed pisanym kodem. Kwadratowe nawiasy kwadratowe[[Prototype]]
są celowe i stanowią konwencję specyfikacji ECMAScript oznaczającą gniazda wewnętrzne.Wartość wskazywana przez
[[Prototype]]
obiekt jest potocznie nazywana „prototypem tego obiektu”.Jeśli uzyskujesz dostęp do właściwości za pomocą notacji dot (
obj.propName
) lub nawiasu klamrowego (obj['propName']
), a obiekt nie ma bezpośrednio takiej właściwości (tj. Własność własna , którą można sprawdzić przezobj.hasOwnProperty('propName')
), środowisko wykonawcze szuka właściwości o tej nazwie w obiekcie, do którego się odwołuje przez[[Prototype]]
zamiast. Jeśli[[Prototype]]
również nie ma takiej właściwości,[[Prototype]]
jest ona kolejno sprawdzana i tak dalej. W ten sposób prototypowy łańcuch oryginalnego obiektu przechodzi do momentu znalezienia dopasowania lub osiągnięcia jego końca. Na szczycie łańcucha prototypów znajduje sięnull
wartość.Nowoczesne implementacje JavaScript umożliwiają dostęp do odczytu i / lub zapisu
[[Prototype]]
w następujący sposób:new
napędu (konfiguruje łańcucha prototyp na domyślnej obiektu zwróconej od funkcji konstruktora)extends
kluczowe (konfiguruje łańcuch prototypów podczas korzystania ze składni klasy),Object.create
ustawi dostarczony argument jako[[Prototype]]
wynikowy obiekt,Object.getPrototypeOf
iObject.setPrototypeOf
(pobierz / ustaw tworzenie obiektu[[Prototype]]
po ) i__proto__
(podobna do 4.)Object.getPrototypeOf
iObject.setPrototypeOf
są preferowane__proto__
, po części dlatego, że zachowanieo.__proto__
jest niezwykłe, gdy obiekt ma prototypnull
.Obiekt
[[Prototype]]
jest początkowo ustawiany podczas tworzenia obiektu.Jeśli utworzysz nowy obiekt za pomocą
new Func()
, obiekt[[Prototype]]
zostanie domyślnie ustawiony na obiekt, do którego odnosi sięFunc.prototype
.Należy pamiętać, że dlatego wszystkie klasy i wszystkie funkcje, których można używać z
new
operatorem, mają własność nazwaną.prototype
oprócz własnego[[Prototype]]
gniazda wewnętrznego. To podwójne użycie słowa „prototyp” jest źródłem niekończących się nieporozumień wśród nowych użytkowników języka.Korzystanie
new
z funkcji konstruktora pozwala nam symulować klasyczne dziedziczenie w JavaScript; chociaż system dziedziczenia JavaScript jest - jak widzieliśmy - prototypowy, a nie oparty na klasach.Przed wprowadzeniem składni klas do JavaScript funkcje konstruktora były jedynym sposobem symulacji klas. Możemy myśleć o właściwościach obiektu, do którego odwołuje się właściwość funkcji konstruktora,
.prototype
jako wspólnych elementach; to znaczy. członkowie, którzy są tacy sami dla każdej instancji. W systemach opartych na klasach metody są implementowane w taki sam sposób dla każdej instancji, więc metody są dodawane koncepcyjnie do.prototype
właściwości; pola obiektu są jednak specyficzne dla instancji i dlatego są dodawane do samego obiektu podczas budowy.Bez składni klas programiści musieli ręcznie skonfigurować łańcuch prototypów, aby osiągnąć funkcjonalność zbliżoną do klasycznego dziedziczenia. Doprowadziło to do przewagi różnych sposobów osiągnięcia tego celu.
Oto jeden ze sposobów:
... a oto inny sposób:
Składnia klas wprowadzona w ES2015 upraszcza rzeczy, zapewniając
extends
jako „jedyny prawdziwy sposób” konfiguracji łańcucha prototypów w celu symulacji klasycznego dziedziczenia w JavaScript.Podobnie, jak w powyższym kodzie, jeśli użyjesz składni klasy, aby utworzyć nowy obiekt w następujący sposób:
... wynikowy obiekt
[[Prototype]]
zostanie ustawiony na instancjęParent
, której[[Prototype]]
z kolei jestParent.prototype
.Wreszcie, jeśli utworzysz nowy obiekt za pomocą
Object.create(foo)
, wynikowy obiekt[[Prototype]]
zostanie ustawiony nafoo
.źródło
W języku implementującym klasyczne dziedziczenie, takim jak Java, C # lub C ++, zaczynasz od utworzenia klasy - schematu dla swoich obiektów - a następnie możesz utworzyć nowe obiekty z tej klasy lub możesz rozszerzyć klasę, definiując nową klasę, która jest rozszerzana oryginalna klasa.
W JavaScript najpierw tworzysz obiekt (nie ma pojęcia klasy), a następnie możesz rozszerzać własny obiekt lub tworzyć z niego nowe obiekty. Nie jest to trudne, ale trochę obce i trudne do metabolizmu dla kogoś przyzwyczajonego do klasycznego sposobu.
Przykład:
Do tej pory rozszerzałem podstawowy obiekt, teraz tworzę inny obiekt, a następnie dziedziczę po Person.
Pokaż fragment kodu
Chociaż, jak powiedziano, nie mogę wywołać setAmountDue (), getAmountDue () na Osobie.
źródło
Customer.prototype = new Person();
linii MDN pokazuje przykład, używającCustomer.prototype = Object.create(Person.prototype)
i stwierdza, że „częstym błędem jest tutaj użycie„ new Person () ”” . źródłoJest to bardzo prosty prototypowy model obiektowy, który podczas objaśnienia byłby traktowany jako próbka, bez komentarza:
Jest kilka kluczowych punktów, które musimy wziąć pod uwagę przed omówieniem koncepcji prototypu.
1- Jak faktycznie działają funkcje JavaScript:
Aby zrobić pierwszy krok, musimy dowiedzieć się, jak faktycznie działają funkcje JavaScript, jako klasa taka jak funkcja wykorzystująca
this
słowo kluczowe lub po prostu jako zwykła funkcja z argumentami, co robi i co zwraca.Powiedzmy, że chcemy stworzyć
Person
model obiektowy. ale w tym kroku będę próbował zrobić dokładnie to samo bez użycia słowa kluczowegoprototype
inew
.Więc na tym etapie
functions
,objects
athis
słowa kluczowego, to wszystko, co mamy.Pierwszym pytaniem byłoby, w jaki sposób
this
słowo kluczowe może być przydatne bez użycianew
słowa kluczowego .Aby odpowiedzieć, powiedzmy, że mamy pusty obiekt i dwie funkcje, takie jak:
a teraz bez użycia
new
słowa kluczowego, w jaki sposób moglibyśmy korzystać z tych funkcji. JavaScript ma więc 3 różne sposoby:za. pierwszym sposobem jest wywołanie funkcji jako zwykłej funkcji:
w tym przypadku byłby to bieżący obiekt kontekstu, którym zwykle jest
window
obiekt globalny w przeglądarce lubGLOBAL
wNode.js
. Oznacza to, że mielibyśmy, window.name w przeglądarce lub GLOBAL.name w Node.js, z „George” jako jego wartością.b. Możemy dołączyć je do obiektu jako jego właściwości
- Najłatwiej to zrobić, modyfikując puste
person
obiekt, na przykład:w ten sposób możemy je nazwać:
a teraz
person
obiekt jest jak:- Innym sposobem dołączenia właściwości do obiektu jest użycie
prototype
tego obiektu, który można znaleźć w dowolnym obiekcie JavaScript o nazwie__proto__
, i próbowałem wyjaśnić to trochę w części podsumowującej. Możemy więc uzyskać podobny wynik, wykonując:Ale w ten sposób faktycznie modyfikujemy
Object.prototype
, ponieważ za każdym razem, gdy tworzymy obiekt JavaScript za pomocą literals ({ ... }
), jest on tworzony na podstawieObject.prototype
, co oznacza, że zostaje on dołączony do nowo utworzonego obiektu jako atrybut o nazwie__proto__
, więc jeśli go zmienimy , podobnie jak w przypadku naszego poprzedniego fragmentu kodu, wszystkie obiekty JavaScript zostałyby zmienione, co nie jest dobrą praktyką. Więc jaka może być teraz lepsza praktyka:a teraz inne przedmioty są spokojne, ale nadal nie wydaje się to dobrą praktyką. Mamy więc jeszcze jedno rozwiązanie, ale aby skorzystać z tego rozwiązania, powinniśmy wrócić do tego wiersza kodu, w którym
person
utworzono obiekt (var person = {};
), a następnie zmienić go w następujący sposób:tworzy nowy JavaScript
Object
i dołącza gopropertiesObject
do pliku__proto__
atrybutu. Aby upewnić się, że możesz:Problem w tym, że masz dostęp do wszystkich właściwości zdefiniowanych
__proto__
na pierwszym poziomieperson
obiektu (więcej szczegółów znajdziesz w części podsumowującej).jak widzisz, używając dowolnego z tych dwóch sposobów
this
wskazywałoby dokładnie naperson
obiekt.do. JavaScript ma inny sposób na zapewnienie funkcji
this
, która polega na wywołaniu lub zastosowaniu do wywołania funkcji.i
w ten sposób, który jest moim ulubionym, możemy łatwo wywoływać nasze funkcje, takie jak:
lub
te 3 metody są ważnymi początkowymi krokami do zrozumienia funkcjonalności .prototypu.
2- Jak działa
new
słowo kluczowe?to jest drugi krok do zrozumienia
.prototype
funkcjonalności. oto, czego używam do symulacji procesu:w tej części postaram się wykonać wszystkie kroki, które wykonuje JavaScript, bez użycia
new
słowa kluczowego iprototype
, gdy używasznew
słowa kluczowego. więc kiedy to robimynew Person("George")
,Person
funkcja służy jako konstruktor. Oto, co robi JavaScript, jeden po drugim:za. po pierwsze tworzy pusty obiekt, w zasadzie pusty skrót, taki jak:
b. następnym krokiem JavaScript jest dołączenie wszystkich prototypowych obiektów do nowo utworzonego obiektu
mamy
my_person_prototype
tutaj podobny do obiektu prototypowego.To nie jest sposób, w jaki JavaScript faktycznie dołącza właściwości zdefiniowane w prototypie. Rzeczywisty sposób związany jest z koncepcją łańcucha prototypów.
za. & b. Zamiast tych dwóch kroków możesz uzyskać dokładnie taki sam wynik, wykonując:
teraz możemy wywołać
getName
funkcję w naszymmy_person_prototype
:do. następnie przekazuje ten obiekt do konstruktora,
możemy to zrobić za pomocą naszej próbki, takiej jak:
lub
wtedy konstruktor może zrobić, co chce, ponieważ to wewnątrz tego konstruktora jest obiekt, który został właśnie utworzony.
teraz wynik końcowy przed symulacją innych kroków: Object {name: "George"}
Podsumowanie:
Zasadniczo, gdy używasz nowego słowa kluczowego w funkcji, wywołujesz tę funkcję, a ta funkcja służy jako konstruktor, więc mówiąc:
JavaScript wewnętrznie tworzy obiekt, pusty skrót, a następnie przekazuje ten obiekt do konstruktora, a następnie konstruktor może zrobić co chce, ponieważ to wewnątrz tego konstruktora jest właśnie utworzonym obiektem, a następnie daje ten obiekt oczywiście jeśli nie użyłeś instrukcji return w swojej funkcji lub jeśli umieściłeś
return undefined;
na końcu treści funkcji.Kiedy JavaScript zaczyna szukać właściwości na obiekcie, pierwszą rzeczą, którą robi, jest wyszukiwanie na tym obiekcie. A potem jest tajna właściwość,
[[prototype]]
którą zwykle mamy,__proto__
a ta właściwość właśnie patrzy na JavaScript. A kiedy przegląda__proto__
, o ile jest to kolejny obiekt JavaScript, ma swój własny__proto__
atrybut, idzie w górę i w górę, aż dojdzie do punktu, w którym następny__proto__
jest pusty. Punkt jest jedynym obiektem w JavaScript, którego__proto__
atrybut ma wartość null, toObject.prototype
obiekt:i tak działa dziedziczenie w JavaScript.
Innymi słowy, gdy masz właściwość prototypową funkcji i wywołujesz nową funkcję, po zakończeniu JavaScript w poszukiwaniu tego nowo utworzonego obiektu pod kątem właściwości, przejdzie on do funkcji
.prototype
i możliwe jest, że ten obiekt ma swoją własny wewnętrzny prototyp. i tak dalej.źródło
__proto__
najpierw usuniesz wszystkie właściwości prototypu najwyższego poziomu, a następnie będziesz mieć świeżą bazę proto, która nie będzie już udostępniana, chyba że ją udostępnisz.Siedem prototypów Koanów
Gdy Ciro San zszedł po Mount Fire Fox po głębokiej medytacji, jego umysł był czysty i spokojny.
Jego ręka była jednak niespokojna i sama chwyciła pędzel i zanotowała następujące nuty.
0) Dwie różne rzeczy można nazwać „prototypem”:
własność prototypu, jak w
obj.prototype
prototypowa własność wewnętrzna, oznaczona jak
[[Prototype]]
w ES5 .Można go odzyskać za pomocą ES5
Object.getPrototypeOf()
.Firefox udostępnia go za pośrednictwem
__proto__
właściwości jako rozszerzenie. ES6 wspomina teraz o niektórych opcjonalnych wymaganiach dotyczących__proto__
.1) Te pojęcia istnieją, aby odpowiedzieć na pytanie:
Intuicyjnie klasyczne dziedziczenie powinno wpływać na wyszukiwanie właściwości.
2)
__proto__
służy do.
wyszukiwania właściwości kropki jak wobj.property
..prototype
nie jest używany do wyszukiwania bezpośrednio, tylko pośrednio, ponieważ określa__proto__
przy tworzeniu obiektu za pomocąnew
.Kolejność wyszukiwania to:
obj
właściwości dodane przy pomocyobj.p = ...
lubObject.defineProperty(obj, ...)
obj.__proto__
obj.__proto__.__proto__
itd__proto__
sąnull
, wróćundefined
.Jest to tak zwany łańcuch prototypowy .
Możesz uniknąć
.
wyszukiwania za pomocąobj.hasOwnProperty('key')
iObject.getOwnPropertyNames(f)
3) Istnieją dwa główne sposoby ustawienia
obj.__proto__
:new
:następnie
new
ustawił:To jest miejsce, gdzie
.prototype
wykorzystywane wystąpią.Object.create
:zestawy:
4) Kod:
Odpowiada poniższemu diagramowi (niektóre
Number
rzeczy zostały pominięte):Ten schemat pokazuje wiele predefiniowanych węzłów obiektowych:
null
Object
Object.prototype
Function
Function.prototype
1
Number.prototype
(można znaleźć za pomocą(1).__proto__
nawiasu obowiązkowego, aby spełnić składnię)Nasze 2 wiersze kodu utworzyły tylko następujące nowe obiekty:
f
F
F.prototype
i
jest teraz własnością,f
ponieważ kiedy to zrobisz:oblicza
F
sięthis
jako wartość, któranew
zostanie zwrócona, a następnie przypisanaf
.5)
.constructor
zazwyczaj pochodziF.prototype
przez.
wyszukiwarkę:Kiedy piszemy
f.constructor
, JavaScript.
sprawdza, jak:f
nie ma.constructor
f.__proto__ === F.prototype
ma.constructor === F
, więc weź toWynik
f.constructor == F
jest intuicyjnie poprawny, ponieważF
służy do konstruowaniaf
, np. Ustawiania pól, podobnie jak w klasycznych językach OOP.6) Klasyczną składnię dziedziczenia można osiągnąć, manipulując łańcuchami prototypów.
ES6 dodaje słowa kluczowe
class
iextends
, które w większości są cukrem składniowym dla wcześniej możliwego szaleństwa manipulacji prototypem.Uproszczony schemat bez wszystkich predefiniowanych obiektów:
Zastanówmy się, jak działają następujące elementy:
Pierwszy wiersz ustawiony
c.i
jest1
zgodnie z opisem w „4)”.W drugiej linii, kiedy robimy:
.inc
znajduje się w[[Prototype]]
łańcuchu:c
->C
->C.prototype
->inc
X.Y()
, JavaScript automatycznie ustawia sięthis
na wartość równąX
wY()
wywołaniu funkcji!Ta sama logika wyjaśnia również
d.inc
id.inc2
.W tym artykule https://javascript.info/class#not-just-a-syntax-sugar wspomina o dalszych efektach, o których
class
warto wiedzieć. Niektóre z nich mogą nie być osiągalne bezclass
słowa kluczowego (sprawdź, które TODO):[[FunctionKind]]:"classConstructor"
, co zmusza konstruktora do wywołania z nowym: Jaki jest powód, dla którego konstruktory klasy ES6 nie mogą być wywoływane jako normalne funkcje?Object.defineProperty
.use strict
. Można to zrobić jawnieuse strict
dla każdej funkcji, co jest co prawda uciążliwe.źródło
.
działa wyszukiwanie (i ile kopii danych jest zrobionych) . Więc postanowiłem zrozumieć ten punkt. Reszta to Google + posty na blogu + tłumacz Js pod ręką. :)sets f.constructor = F
Część była rażąco błędne i sprzeczne z dalszych sekcjach:.constructor
znaleziono poprzez.
odnośnika na łańcuchu prototypów. Naprawiono to teraz.f
prototyp jest ustawionyF
dopiero na etapie budowy;f
nie będzie o tym wiedział ani się nim przejmowaćF.prototype
w żadnym momencie po jego pierwszym zbudowaniu.prototype
pozwala tworzyć zajęcia. jeśli nie używaszprototype
, staje się statyczny.Oto krótki przykład.
W powyższym przypadku masz test wywołania funkcji statycznej. Dostęp do tej funkcji można uzyskać tylko poprzez obj.test, w którym można sobie wyobrazić, że jest klasą.
gdzie jak w poniższym kodzie
Obiekt stał się klasą, którą można teraz tworzyć. Może istnieć wiele instancji obj i wszystkie mają
test
funkcję.Powyżej jest moje zrozumienie. Robię z niej wiki społeczności, aby ludzie mogli mnie poprawić, jeśli się mylę.
źródło
prototype
jest własnością funkcji konstruktora, a nie instancji, tzn. Twój kod jest nieprawidłowy! Być może miałeś na myśli niestandardową właściwość__proto__
przedmiotów, ale to zupełnie inna bestia ...Po przeczytaniu tego wątku czuję się pomylony z łańcuchem prototypów JavaScript, a potem znalazłem te wykresy
http://iwiki.readthedocs.org/en/latest/javascript/js_core.html#inheritance
jest to przejrzysty wykres pokazujący dziedziczenie JavaScript według Prototype Chain
i
http://www.javascriptbank.com/javascript/article/JavaScript_Classical_Inheritance/
ten zawiera przykład z kodem i kilkoma ładnymi schematami.
Mam nadzieję, że zrozumienie łańcucha prototypów JavaScript jest również pomocne.
źródło
[[Prototype]]
to znaczy?Każdy obiekt ma wewnętrzną właściwość [[Prototyp]] , łącząc go z innym obiektem:
W tradycyjnym javascript połączony obiekt jest
prototype
własnością funkcji:Niektóre środowiska udostępniają [[Prototyp]] jako
__proto__
:Tworzenia [[prototyp]] link, podczas tworzenia obiektu.
Te instrukcje są równoważne:
Tak naprawdę nie możesz zobaczyć link target (
Object.prototype
) w nowej instrukcji; zamiast tego cel jest sugerowany przez konstruktor (Object
).Zapamiętaj:
prototype
właściwość, początkowo przechowującą pusty obiekt.prototype
właściwością ich konstruktora.prototype
właściwość pozostanie nieużywana.new
.źródło
Object.create()
dokumentów , @sam. Linki do__proto__
iObject.prototype
byłyby miłymi ulepszeniami. Podobały mi się twoje przykłady działania prototypów z konstruktorami iObject.create()
, ale były to prawdopodobnie długie i mniej istotne elementy, których chciałeś się pozbyć.JavaScript nie ma dziedziczenia w zwykłym znaczeniu, ale ma łańcuch prototypów.
łańcuch prototypowy
Jeśli członka obiektu nie można znaleźć w obiekcie, szuka go w łańcuchu prototypów. Łańcuch składa się z innych przedmiotów. Dostęp do prototypu danej instancji można uzyskać za pomocą
__proto__
zmiennej. Każdy obiekt ma jeden, ponieważ nie ma różnicy między klasami i instancjami w javascript.Zaletą dodania funkcji / zmiennej do prototypu jest to, że musi on znajdować się w pamięci tylko raz, a nie dla każdej instancji.
Jest także przydatny do dziedziczenia, ponieważ łańcuch prototypów może składać się z wielu innych obiektów.
źródło
Ten artykuł jest długi. Ale jestem pewien, że wyczyści większość twoich zapytań dotyczących „prototypowej” natury dziedziczenia JavaScript. I nawet więcej. Przeczytaj cały artykuł.
JavaScript zasadniczo ma dwa rodzaje typów danych
Bez obiektów
Poniżej podano typy danych niebędące obiektami
Te typy danych zwracają następujące, gdy używasz operatora typeof
typeof „string literal” (lub zmienna zawierająca literał ciąg) === „ciąg”
typ 5 (lub dowolny literał liczbowy lub zmienna zawierająca literał liczbowy lub NaN lub Infynity ) === „liczba”
typeof true (lub false lub zmienna zawierająca true lub false ) === „boolean”
typeof undefined (lub niezdefiniowana zmienna lub zmienna zawierająca niezdefiniowany ) === „niezdefiniowany”
W ciąg , liczba i wartość logiczna typy danych mogą być reprezentowane zarówno jako obiekty i dla obiektów .Przy są reprezentowane jako obiekty ich typeof jest zawsze === „przedmiot”. Powrócimy do tego, gdy zrozumiemy typy danych obiektowych.
Obiekty
Typy danych obiektów można dalej podzielić na dwa typy
Obiekty typu Function to te, które zwracają ciąg „function” z operatorem typeof . Do tej kategorii należą wszystkie funkcje zdefiniowane przez użytkownika i wszystkie obiekty wbudowane w JavaScript, które mogą tworzyć nowe obiekty za pomocą nowego operatora. Na przykład
Więc typeof (Object) === typeof (String) === typeof (Number) === typeof (Boolean) === typeof (Array) === typeof (RegExp) === typeof (Function) == = typeof (UserDefinedFunction) === „funkcja”
Wszystkie obiekty typu Function są w rzeczywistości instancjami wbudowanego obiektu JavaScript Function (w tym obiektu Function, tzn. Jest on rekurencyjnie zdefiniowany). To tak, jakby te obiekty zostały zdefiniowane w następujący sposób
Jak wspomniano, obiekty typu Funkcja mogą dalej tworzyć nowe obiekty za pomocą nowego operatora . Na przykład obiekt typu Object , String , Number , Boolean , Array , RegExp Or UserDefinedFunction można utworzyć za pomocą
W ten sposób tworzone obiekty są wszystkie obiekty typu Funkcja pokoje i powrót ich typeof === „przedmiot” . We wszystkich tych przypadkach obiekt „a” nie może dalej tworzyć obiektów za pomocą operatora new. Więc następujące jest złe
Wbudowany obiekt Math to typeof === „obiekt” . Dlatego nowy operator typu Math nie może zostać utworzony przez nowy operator.
Zauważ również, że funkcje Object , Array i RegExp mogą tworzyć nowy obiekt nawet bez użycia operatora new . Jednak następujące nie.
Funkcje zdefiniowane przez użytkownika są szczególnym przypadkiem.
Ponieważ obiekty typu Function mogą tworzyć nowe obiekty, nazywane są również Konstruktorami .
Każdy konstruktor / funkcja (wbudowana lub zdefiniowana przez użytkownika), gdy jest zdefiniowana automatycznie, ma właściwość o nazwie „prototyp”, której wartość jest domyślnie ustawiona jako obiekt. Sam obiekt ma właściwość o nazwie „konstruktor”, która domyślnie odwołuje się do konstruktora / funkcji .
Na przykład kiedy definiujemy funkcję
następuje automatycznie
Ta właściwość „prototypowa” jest obecna tylko w obiektach typu Function (i nigdy w obiektach innych niż Function ).
Dzieje się tak, ponieważ gdy tworzony jest nowy obiekt (przy użyciu nowego operatora), dziedziczy on wszystkie właściwości i metody z bieżącego obiektu prototypowego funkcji Constructor, tj. Wewnętrznego odwołania W nowo utworzonym obiekcie tworzone które odwołuje się do obiektu, do którego odwołuje się bieżący obiekt prototypowy funkcji Constructor.
To „wewnętrzne odniesienie”, które jest tworzone w obiekcie do odwoływania się do odziedziczonych właściwości, jest znane jako prototyp obiektu (który odwołuje się do obiektu, do którego odwołuje się właściwość „prototypu” Konstruktora, ale różni się od niego). W przypadku dowolnego obiektu (funkcji lub funkcji) można go pobrać za pomocą metody Object.getPrototypeOf () . Za pomocą tej metody można prześledzić łańcuch prototypowy obiektu.
Ponadto każdy utworzony obiekt ( typ funkcji lub typ niefunkcyjny ) ma właściwość „konstruktora”, która jest dziedziczona z obiektu, do którego odwołuje się właściwość prototypowa funkcji konstruktora. Domyślnie ta właściwość „konstruktora” odwołuje się do funkcji konstruktora, która ją utworzyła (jeśli jest to funkcja konstruktora domyślny „prototyp” nie zostanie zmieniony).
Dla wszystkich obiektów typu Function funkcją konstruktora jest zawsze funkcja Function () {}
W przypadku obiektów niefunkcjonalnych (np. Obiekt JavaScript Built in Math) funkcja konstruktora to funkcja, która go utworzyła. Dla obiektu Math jest to funkcja Object () {} .
Wszystkie powyższe pojęcia mogą być nieco zniechęcające do zrozumienia bez żadnego dodatkowego kodu. Proszę przejść przez następujący kod wiersz po wierszu, aby zrozumieć pojęcie. Spróbuj go wykonać, aby lepiej zrozumieć.
Łańcuch prototypów każdego obiektu ostatecznie powraca do Object.prototype (który sam nie ma żadnego obiektu prototypowego). Poniższy kod może służyć do śledzenia łańcucha prototypów obiektu
Łańcuch prototypów różnych obiektów działa w następujący sposób.
Aby utworzyć obiekt bez prototypu, użyj:
Można by pomyśleć, że ustawienie właściwości prototypowej Konstruktora na wartość null spowoduje utworzenie obiektu z prototypem o wartości NULL. Jednak w takich przypadkach prototyp nowo utworzonego obiektu jest ustawiany na Object.prototype, a jego konstruktor jest ustawiony na funkcję Object. Pokazuje to poniższy kod
Poniżej w podsumowaniu tego artykułu
Tylko obiekty typu Funkcja mogą utworzyć nowy obiekt za pomocą operatora new . Obiekty utworzone w ten sposób są obiektami typu Non Function . Obiekty typu Non Function nie mogą dalej tworzyć obiektu za pomocą operatora new .
Wszystkie obiekty typu Funkcja domyślnie mają właściwość „prototypu” . Ta właściwość „prototypowa” odwołuje się do obiektu, który ma właściwość „konstruktora”, która domyślnie odwołuje się do samego obiektu typu Funkcja .
Wszystkie obiekty ( typ funkcji i typ inny niż funkcja ) mają właściwość „konstruktor”, która domyślnie odwołuje się do obiektu typu obiekt / konstruktor, który go utworzył.
Każdy obiekt, który zostanie utworzony wewnętrznie, odwołuje się do obiektu, do którego odnosi się właściwość „prototypu” konstruktora, który go utworzył. Ten obiekt jest znany jako prototyp utworzonego obiektu (który różni się od właściwości „prototypowej” obiektów typu Function, do której się odwołuje). W ten sposób utworzony obiekt może uzyskać bezpośredni dostęp do metod i właściwości zdefiniowanych w obiekcie, do którego odwołuje się właściwość „prototypu” Konstruktora (w momencie tworzenia obiektu).
Wykonania prototypu obiektu (i stąd jego nazwy właściwości dziedziczne) mogą być pobierane za pomocą Object.getPrototypeOf () metody. W rzeczywistości ta metoda może być używana do poruszania się po całym łańcuchu prototypów obiektu.
Łańcuch prototypów każdego obiektu ostatecznie powraca do Object.prototype (chyba że obiekt jest tworzony za pomocą Object.create (null), w którym to przypadku obiekt nie ma prototypu).
typeof (new Array ()) === „obiekt” wynika z projektu języka, a nie z pomyłki wskazanej przez Douglasa Crockforda
Ustawienie właściwości prototypu Konstruktora na null (lub niezdefiniowany, liczba, prawda, fałsz, łańcuch) nie spowoduje utworzenia obiektu z prototypem o wartości NULL. W takich przypadkach prototyp nowo utworzonego obiektu jest ustawiany na Object.prototype, a jego konstruktor jest ustawiony na funkcję Object.
Mam nadzieję że to pomoże.
źródło
Koncepcja
prototypal
dziedziczenia jest jedną z najbardziej skomplikowanych dla wielu programistów. Spróbujmy zrozumieć źródło problemu, abyprototypal inheritance
lepiej zrozumieć . Zacznijmy odplain
funkcji.Jeśli używamy
new
operatora naTree function
, nazywamy go jakoconstructor
funkcję.Każda
JavaScript
funkcja maprototype
. Po zalogowaniuTree.prototype
otrzymujesz ...Jeśli spojrzysz na powyższe
console.log()
dane wyjściowe, możesz zobaczyć właściwość konstruktoraTree.prototype
i__proto__
właściwość również.__proto__
Reprezentujeprototype
że tafunction
oparta jest wyłączony, a ponieważ jest to po prostu zwykłyJavaScript function
bezinheritance
skonfigurować jeszcze, że odnosi się doObject prototype
co jest czymś po prostu wbudowane w JavaScript ...https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/prototype
Ma takie rzeczy jak
.toString, .toValue, .hasOwnProperty
itp ...__proto__
który został przyniesiony moja mozilla jest przestarzała i jest zastąpiona przezObject.getPrototypeOf
metodę uzyskaniaobject's prototype
.Dodajmy metodę do naszego
Tree
prototype
.Zmodyfikowaliśmy
Root
i dodaliśmyfunction
do niego gałąź.To znaczy, kiedy utworzyć
instance
zTree
, można nazwać to zabranch
metody.Możemy również dodać
primitives
lubobjects
do naszegoPrototype
.Dodajmy
child-tree
do naszegoTree
.Tutaj
Child
dziedziczyprototype
po drzewie, my tutaj robimyObject.create()
metodą tworzenia nowego obiektu na podstawie tego, co przekazujesz, oto jestTree.prototype
. W tym przypadku robimy ustawienie prototypu Childa na nowy obiekt, który wygląda identycznie jakTree
prototyp. Następnie ustawiamyChild's constructor to Child
, jeśli nie, wskazujeTree()
.Child
teraz ma swoją własnąprototype
,__proto__
punkty doTree
iTree's prototype
punkty do bazyObject
.Teraz można utworzyć
instance
zChild
zawołaniebranch
, który jest dostępny w oryginalnieTree
. Tak naprawdę nie zdefiniowaliśmy naszegobranch
wChild prototype
. ALE, wRoot prototype
którym dziedziczy Dziecko.W JS wszystko nie jest przedmiotem, wszystko może działać jak obiekt.
Javascript
ma takie prymitywy jakstrings, number, booleans, undefined, null.
nie sąobject(i.e reference types)
, ale z pewnością mogą zachowywać się jakobject
. Spójrzmy na przykład tutaj.W pierwszym wierszu tego wpisu
primitive
do nazwy przypisana jest wartość ciągu. Druga linia traktuje nazwę jakobject
i wywołujecharAt(0)
za pomocą notacji kropkowej.Oto, co dzieje się za kulisami: // co
JavaScript
robi silnikString object
Istnieje tylko jedno oświadczenie zanim zostanie zniszczony (proces zwanyautoboxing
). Wróćmy do naszegoprototypal
inheritance
.Javascript
obsługuje dziedziczenie poprzezdelegation
na podstawieprototypes
.Function
maprototype
właściwość, która odnosi się do innego obiektu.properties/functions
są oglądane zobject
samego siebie lub za pośrednictwemprototype
łańcucha, jeśli nie istniejeA
prototype
w JS jest obiektem, któryyields
ty do rodzica innegoobject
. [tzn. delegacja]Delegation
oznacza, że jeśli nie jesteś w stanie nic zrobić, powiesz komuś innemu, aby zrobił to za Ciebie.https://jsfiddle.net/say0tzpL/1/
Jeśli spojrzysz na powyższe skrzypce, pies ma dostęp do
toString
metody, ale nie jest w nim dostępna, ale jest dostępna za pośrednictwem łańcucha prototypów, do którego deleguje sięObject.prototype
Jeśli spojrzysz na poniższy, staramy się uzyskać dostęp do
call
metody, która jest dostępna w każdymfunction
.https://jsfiddle.net/rknffckc/
Jeśli spojrzysz na powyższe skrzypce,
Profile
funkcja ma dostęp docall
metody, ale nie jest w niej dostępna, ale dostępna za pośrednictwem łańcucha prototypów, do którego deleguje sięFunction.prototype
Uwaga:
prototype
jest właściwością konstruktora funkcji, natomiast__proto__
jest własnością obiektów zbudowanych z konstruktora funkcji. Każda funkcja maprototype
właściwość, której wartość jest pustaobject
. Kiedy tworzymy wystąpienie funkcji, otrzymujemy właściwość wewnętrzną[[Prototype]]
lub do__proto__
której odwołania jest prototyp Funkcjiconstructor
.Powyższy schemat wygląda na nieco skomplikowany, ale pokazuje cały obraz tego, jak to zrobić
prototype chaining
działa. Przejdźmy przez to powoli:Istnieją dwa przykład
b1
ab2
, którego konstruktor jestBar
i nadrzędne foo i ma dwie metody z łańcucha prototypówidentify
ispeak
poprzezBar
iFoo
https://jsfiddle.net/kbp7jr7n/
Jeśli spojrzysz na powyższy kod, mamy
Foo
konstruktora, który ma metodęidentify()
iBar
konstruktora, który maspeak
metodę. Tworzymy dwaBar
instancjib1
ib2
którego typ jest dominującaFoo
. Teraz, podczas wywoływaniaspeak
metodyBar
, jesteśmy w stanie zidentyfikować, kto dzwoni do mówienia za pośrednictwemprototype
łańcucha.Bar
teraz ma wszystkie metody,Foo
które są zdefiniowane w jegoprototype
. Chodźmy kopać dalej w zrozumieniuObject.prototype
iFunction.prototype
i jak są one powiązane. Jeśli przyjrzeć się konstruktoraFoo
,Bar
iObject
sąFunction constructor
.prototype
OBar
toFoo
,prototype
zeFoo
jest w stanieObject
i jeśli spojrzeć bacznieprototype
zFoo
jest związaneObject.prototype
.Zanim zamkniemy to, po prostu napiszmy tutaj mały fragment kodu, aby podsumować wszystko powyżej . Używamy
instanceof
tutaj operatora, aby sprawdzić, czyobject
ma w swoimprototype
łańcuchuprototype
właściwość tego,constructor
który poniżej podsumowuje cały duży diagram.Mam nadzieję, że ten dodatek zawiera pewne informacje, wiem, że ten rodzaj może być duży do uchwycenia ... w prostych słowach to tylko obiekty powiązane z obiektami !!!!
źródło
Interfejs do klas standardowych staje się rozszerzalny. Na przykład używasz
Array
klasy i musisz również dodać niestandardowy serializator dla wszystkich obiektów tablicy. Czy spędzasz czas na kodowaniu podklasy, czy używasz kompozycji lub ... Właściwość prototyp rozwiązuje to, pozwalając użytkownikom kontrolować dokładny zestaw elementów / metod dostępnych dla klasy.Pomyśl o prototypach jako o dodatkowym wskaźniku vtable. Gdy brakuje niektórych członków oryginalnej klasy, prototyp jest sprawdzany w czasie wykonywania.
źródło
Może to pomóc w podzieleniu łańcuchów prototypów na dwie kategorie.
Zastanów się nad konstruktorem:
Wartość
Object.getPrototypeOf(Person)
jest funkcją. W rzeczywistości tak jestFunction.prototype
. PonieważPerson
został utworzony jako funkcja, ma ten sam prototypowy obiekt funkcji, co wszystkie funkcje. Jest taki sam jakPerson.__proto__
, ale tej właściwości nie należy używać. W każdym razie wraz zObject.getPrototypeOf(Person)
tobą skutecznie wejdź po drabinie łańcucha prototypów.Łańcuch w górę wygląda następująco:
Person
→Function.prototype
→Object.prototype
(punkt końcowy)Ważne jest to, że ten łańcuch prototypów ma niewiele wspólnego z obiektami, które
Person
można konstruować . Te skonstruowane obiekty mają swój własny łańcuch prototypowy, a ten łańcuch może potencjalnie nie mieć wspólnego bliskiego przodka z tym wspomnianym powyżej.Weźmy na przykład ten obiekt:
p nie ma bezpośredniego związku łańcucha prototypowego z Osobą . Ich związek jest inny. Obiekt p ma własny łańcuch prototypów. Za pomocą
Object.getPrototypeOf
zobaczysz, że łańcuch jest następujący:p
→Person.prototype
→Object.prototype
(punkt końcowy)W tym łańcuchu nie ma obiektu funkcyjnego (chociaż może to być).
Więc
Person
wydaje się związane z dwóch rodzajów łańcuchów, które żyją własnym życiem. Aby „przeskoczyć” z jednego łańcucha na drugi, użyj:.prototype
: przeskocz z łańcucha konstruktora do łańcucha utworzonego obiektu. Ta właściwość jest więc zdefiniowana tylko dla obiektów funkcji (jaknew
można jej używać tylko w przypadku funkcji)..constructor
: przeskocz z łańcucha utworzonego obiektu do łańcucha konstruktora.Oto wizualna prezentacja dwóch zaangażowanych prototypowych łańcuchów, przedstawionych jako kolumny:
Podsumować:
Nic dziwnego, że nazwa nieruchomości
prototype
może prowadzić do zamieszania. Być może byłoby lepiej, gdyby ta właściwość została nazwanaprototypeOfConstructedInstances
lub coś w tym stylu.Możesz przeskakiwać między dwoma łańcuchami prototypowymi:
Tę symetrię można przełamać, jednoznacznie przypisując do obiektu inny obiekt
prototype
właściwości (więcej na ten temat później).Utwórz jedną funkcję, zdobądź dwa obiekty
Person.prototype
to obiekt, który został utworzony w tym samym czasie, w którym funkcjaPerson
została utworzona. MaPerson
jako konstruktor, chociaż ten konstruktor jeszcze się nie uruchomił. Dwa obiekty są tworzone jednocześnie:Person
samaOba są obiektami, ale mają różne role: konstruuje obiekt funkcji , podczas gdy drugi obiekt reprezentuje prototyp dowolnego obiektu, który zbuduje funkcja. Prototypowy obiekt stanie się rodzicem konstruowanego obiektu w łańcuchu prototypów.
Ponieważ funkcja jest również przedmiotem, ma również swojego rodzica we własnym łańcuchu prototypów, ale pamiętaj, że te dwa łańcuchy dotyczą różnych rzeczy.
Oto niektóre równania, które mogą pomóc w zrozumieniu problemu - wszystkie z nich drukują
true
:Dodawanie poziomów do łańcucha prototypów
Chociaż obiekt prototypowy jest tworzony podczas tworzenia funkcji konstruktora, można go zignorować i przypisać inny obiekt, który powinien być użyty jako prototyp dla kolejnych instancji utworzonych przez ten konstruktor.
Na przykład:
Teraz łańcuch prototypowy t jest o jeden krok dłuższy niż łańcuch p :
t
→p
→Person.prototype
→Object.prototype
(punkt końcowy)Drugi łańcuch prototypów już nie jest:
Thief
iPerson
czy rodzeństwo ma tego samego rodzica w swoim łańcuchu prototypów:Person
}Thief
} →Function.prototype
→Object.prototype
(punkt końcowy)Wcześniej prezentowaną grafikę można następnie rozszerzyć na to (oryginał
Thief.prototype
jest pominięty):Niebieskie linie reprezentują prototypowe łańcuchy, inne kolorowe linie reprezentują inne relacje:
źródło
The Definitive Guide to Object-Oriented JavaScript - bardzo zwięzłe i przejrzyste ~ 30minutowe wyjaśnienie wideo zadanego pytania (Prototypowe dziedziczenie zaczyna się od 5:45 , chociaż wolę posłuchać całego wideo). Autor tego filmu utworzył także stronę internetową do wizualizacji obiektów JavaScript http://www.objectplayground.com/ .
źródło
Przydało mi się wyjaśnienie „łańcucha prototypów” jako konwencji rekurencyjnej, gdy
obj_n.prop_X
się do niego odwołuje:jeśli
obj_n.prop_X
nie istnieje, sprawdźobj_n+1.prop_X
gdzieobj_n+1 = obj_n.[[prototype]]
Jeśli w
prop_X
końcu zostanie znaleziony w k-tym prototypowym obiekcie, toobj_1.prop_X = obj_1.[[prototype]].[[prototype]]..(k-times)..[[prototype]].prop_X
Wykres zależności obiektów JavaScript według ich właściwości można znaleźć tutaj:
http://jsobjects.org
źródło
Kiedy konstruktor tworzy obiekt, obiekt ten domyślnie odwołuje się do właściwości „prototypu” konstruktora w celu rozstrzygania odwołań do właściwości. Do właściwości „prototypu” konstruktora może odwoływać się wyrażenie programowe konstruktor.prototyp, a właściwości dodane do prototypu obiektu są współdzielone, poprzez dziedziczenie, przez wszystkie obiekty współdzielące prototyp.
źródło
Istnieją tutaj dwa odrębne, ale powiązane podmioty, które wymagają wyjaśnienia:
.prototype
Własność funkcji.[[Prototype]]
[1] wszystkich obiektów [2] .To są dwie różne rzeczy.
[[Prototype]]
Nieruchomości:Jest to właściwość istniejąca na wszystkich [2] obiektach.
To, co jest tutaj przechowywane, to inny obiekt, który jako sam obiekt ma
[[Prototype]]
swój własny, który wskazuje na inny obiekt. Ten drugi obiekt ma[[Prototype]]
swój własny. Ta historia trwa, dopóki nie dotrzesz do prototypowego obiektu, który zapewnia metody dostępne dla wszystkich obiektów (np.toString
.).[[Prototype]]
Nieruchomość jest częścią tego, co tworzy[[Prototype]]
łańcuch. Ten łańcuch[[Prototype]]
obiektów jest to, co jest badane, gdy, na przykład,[[Get]]
czy[[Set]]
operacje są wykonywane na obiekcie:.prototype
Nieruchomości:Jest to właściwość, która występuje tylko w funkcjach. Korzystanie z bardzo prostej funkcji:
.prototype
Nieruchomość posiada obiekt , który zostanie przypisany dob.[[Prototype]]
kiedy to zrobićvar b = new Bar
. Możesz to łatwo sprawdzić:Jednym z najważniejszych
.prototype
s jest to, że zObject
funkcji . Ten prototyp zawiera obiekt prototypowy, który[[Prototype]]
zawierają wszystkie łańcuchy. Na nim zdefiniowane są wszystkie dostępne metody dla nowych obiektów:Ponieważ
.prototype
jest to obiekt, ma[[Prototype]]
właściwość. Jeśli nie dokonywać żadnych przypisanych doFunction.prototype
tego,.prototype
„s[[Prototype]]
punktów do prototypowego obiektu (Object.prototype
). Jest to wykonywane automatycznie za każdym razem, gdy tworzysz nową funkcję.W ten sposób za każdym razem, gdy wykonujesz
new Bar;
łańcuch prototypów, masz wszystko zdefiniowaneBar.prototype
i wszystko zdefiniowane naObject.prototype
:Kiedy robisz przypisania do
Function.prototype
wszystkich robisz jest wydłużenie łańcucha prototypów zawierać inny obiekt. To jest jak wstawienie na pojedynczo połączonej liście.To w zasadzie zmienia
[[Prototype]]
łańcuch, pozwalając właściwościom zdefiniowanym na obiekcie przypisanym,Function.prototype
aby były widoczne dla dowolnego obiektu utworzonego przez funkcję.[1: To nikogo nie dezorientuje; udostępnione za pośrednictwem tej
__proto__
własności w wielu implementacjach.[2]: Wszystkie oprócz
null
.źródło
Pozwól, że powiem ci, jak rozumiem prototypy. Nie zamierzam porównywać spadku tutaj z innymi językami. Chciałbym, żeby ludzie przestali porównywać języki i po prostu zrozumieli język jako taki. Zrozumienie prototypów i dziedziczenia prototypów jest tak proste, jak pokażę poniżej.
Prototyp jest jak model, na podstawie którego tworzysz produkt. Kluczową kwestią do zrozumienia jest to, że kiedy tworzysz obiekt przy użyciu innego obiektu jako jego prototypu, połączenie między prototypem a produktem jest trwałe. Na przykład:
Każdy obiekt zawiera wewnętrzną właściwość o nazwie [[prototyp]], do której
Object.getPrototypeOf()
funkcja może uzyskać dostęp .Object.create(model)
tworzy nowy obiekt i ustawia jego właściwość [[prototyp]] na model obiektu . Kiedy to zrobiszObject.getPrototypeOf(product)
, otrzymasz model obiektowy .Właściwości produktu są obsługiwane w następujący sposób:
Takie łączenie obiektów za pomocą właściwości prototypu nazywa się dziedziczeniem prototypowym. Tam jest to takie proste, zgadzasz się?
źródło
Kolejna próba wyjaśnienia dziedziczenia prototypów JavaScript lepszymi zdjęciami
źródło
Rozważ następujący
keyValueStore
obiekt:Mogę utworzyć nową instancję tego obiektu, wykonując następujące czynności:
Każde wystąpienie tego obiektu miałoby następujące właściwości publiczne:
data
get
set
delete
getLength
Załóżmy teraz, że utworzymy 100 wystąpień tego
keyValueStore
obiektu. Nawet jeśliget
,set
,delete
,getLength
zrobi dokładnie to samo dla każdego z tych 100 przypadków, każdy przypadek ma swoją własną kopię tej funkcji.Teraz wyobraźcie sobie, że można mieć tylko jeden
get
,set
,delete
agetLength
kopię, a każdy przypadek będzie odwołać tę samą funkcję. Byłoby to lepsze dla wydajności i wymaga mniej pamięci.Tam właśnie pojawiają się prototypy. Prototyp to „schemat” właściwości, który jest dziedziczony, ale nie jest kopiowany przez instancje. Oznacza to, że istnieje tylko raz w pamięci dla wszystkich instancji obiektu i jest współużytkowany przez wszystkie te instancje.
Teraz
keyValueStore
ponownie rozważ przedmiot. Mógłbym przepisać to w ten sposób:Robi to DOKŁADNIE tak samo jak poprzednia wersja
keyValueStore
obiektu, z tym wyjątkiem, że wszystkie jego metody są teraz umieszczone w prototypie. Oznacza to, że wszystkie ze 100 instancji korzystają teraz z tych czterech metod, zamiast mieć własną kopię.źródło
Podsumowanie:
new
słowem kluczowym, obiekt otrzymuje prototyp. Odniesienie do tego prototypu można znaleźć we__proto__
właściwości nowo utworzonego obiektu.__proto__
właściwość odnosi się doprototype
właściwości funkcji konstruktora.Przykład:
Dlaczego jest to przydatne:
JavaScript ma mechanizm wyszukiwania obiektów nazywa się „dziedziczeniem prototypowym”. Oto, co właściwie robi:
Na przykład:
Aktualizacja:
__proto__
Nieruchomość została zaniechana, chociaż jest realizowane w większości nowoczesnych przeglądarek lepszy sposób, aby uzyskać odniesienie prototyp obiektu będzie:Object.getPrototypeOf()
źródło
Zawsze lubię analogie, jeśli chodzi o rozumienie tego rodzaju rzeczy. Moim zdaniem „dziedziczenie prototypów” jest dość mylące w porównaniu z dziedziczeniem basów klasowych, mimo że prototypy są znacznie prostszym paradygmatem. W rzeczywistości w przypadku prototypów tak naprawdę nie ma dziedziczenia, więc nazwa sama w sobie wprowadza w błąd, jest raczej rodzajem „delegacji”.
Wyobraź to sobie ....
Jesteś w liceum, jesteś w klasie i masz dzisiaj quiz, ale nie masz pióra do wypełnienia swoich odpowiedzi. Doh!
Siedzisz obok swojego przyjaciela Finniusa, który może mieć długopis. Pytasz, a on bezskutecznie rozgląda się po biurku, ale zamiast powiedzieć „nie mam długopisu”, jest miłym przyjacielem i sprawdza, czy ma długopis z drugim przyjacielem Derpem. Derp rzeczywiście ma zapasowy długopis i przekazuje go z powrotem do Finnius, który przekazuje go tobie, aby ukończyć quiz. Derp powierzył pióro długopisowi Finnius, który przekazał ci pióro do użycia.
Ważne jest tutaj to, że Derp nie daje ci długopisu, ponieważ nie masz z nim bezpośredniej relacji .
Jest to uproszczony przykład działania prototypów, w których drzewo danych jest przeszukiwane w celu znalezienia szukanej rzeczy.
źródło
inny schemat pokazujący __proto__ , relacje prototypu i konstruktora :
źródło
Po prostu masz już obiekt,
Object.new
ale nadal nie masz obiektu, gdy używasz składni konstruktora.źródło
Odniesienie: https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Object_prototypes
źródło
Prototype tworzy nowy obiekt przez klonowanie istniejącego obiektu . Tak naprawdę, kiedy myślimy o prototypie, możemy naprawdę pomyśleć o klonowaniu lub zrobieniu kopii czegoś zamiast go wymyślić.
źródło