Pytanie Jak działa JavaScript .prototype?


Nie jestem tym w dynamicznych językach programowania, ale napisałem swój uczciwy udział w kodzie JavaScript. Nigdy tak naprawdę nie rozumiałem tego opartego na prototypach programowania, czy ktoś wie jak to działa?

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

Pamiętam wiele dyskusji z ludźmi od jakiegoś czasu (nie jestem do końca pewien, co robię), ale jak rozumiem, nie ma koncepcji klasy. To tylko obiekt, a instancje tych obiektów są klonami oryginału, prawda?

Ale jaki jest dokładny cel tego .prototype właściwość w JavaScript? W jaki sposób odnosi się do tworzenia obiektów?


Edytować

Te slajdy bardzo pomogło mi zrozumieć ten temat.


1858
2018-02-21 12:31


pochodzenie


John Resig ma kilka slajdów z prototypów funkcji, które były dla mnie pomocne przy analizie tematu (możesz także wprowadzić zmiany w kodzie i zobaczyć, co się dzieje ...) http://ejohn.org/apps/learn/#64 - John Foster
Świetny materiał referencyjny, dla celów utrzymania tego pytania może być pouczający, umieszczając niektóre komentarze ze strony Johna na twojej odpowiedzi, na wypadek, gdyby jego strona uległa zmianom w taki sposób, że twój link nie jest już dostępny. Tak czy inaczej +1, pomógł mi. - Chris
+1 dla twojego linku John Resig's JavaScript Ninja slide # 64. Zaczynając od tego było naprawdę pomocne i mam wrażenie, że poprawnie rozumiem prototypy. - a paid nerd
Czy naprawdę potrzebujemy obiektu funkcjonalnego do zastosowania prototypu? jeśli tak, to dlaczego? - Anshul
To może ci pomóc: webdeveasy.com/javascript-prototype - Naor


Odpowiedzi:


Każdy obiekt JavaScript ma wewnętrzną właściwość o nazwie [[Prototyp]]. Jeśli szukasz nieruchomości przez obj.propName lub obj['propName'] a obiekt nie ma takiej właściwości - którą można sprawdzić za pomocą obj.hasOwnProperty('propName') - środowisko wykonawcze wyszukuje właściwość w obiekcie przywoływanym przez [[Prototyp]]. Jeśli prototyp-obiekt również nie ma takiej właściwości, jego prototyp jest sprawdzany po kolei, przechodząc w ten sposób do oryginalnego obiektu łańcuch prototypów dopóki mecz nie zostanie znaleziony lub nie zostanie osiągnięty koniec.

Niektóre implementacje JavaScript umożliwiają bezpośredni dostęp do właściwości [[Prototype]], np. Za pomocą niestandardowej właściwości o nazwie __proto__. Ogólnie rzecz biorąc, możliwe jest tylko ustawienie prototypu obiektu podczas tworzenia obiektu: Jeśli utworzysz nowy obiekt przez new Func(), właściwość [[Prototype]] obiektu zostanie ustawiona na obiekt, do którego się odwołuje Func.prototype.

Pozwala to na symulowanie klas w JavaScript, chociaż system dziedziczenia JavaScriptu jest - jak widzieliśmy - prototypowy, a nie oparty na klasach:

Wystarczy pomyśleć o funkcjach konstruktora jako klasach i właściwościach prototypu (tj. Obiektu, do którego odwołują się funkcje konstruktora) prototype właściwość) jako członków współużytkowanych, tj. członków, które są takie same dla każdej instancji. W systemach klasowych metody są implementowane w ten sam sposób dla każdej instancji, więc metody są zwykle dodawane do prototypu, podczas gdy pola obiektu są specyficzne dla instancji i dlatego są dodawane do samego obiektu podczas budowy.


927
2018-02-21 13:33



Więc robię coś nie tak, definiując nowe właściwości we właściwościach prototype w moim krótkim opisie? - John Leidegren
Myślę, że właśnie to oznacza posiadanie obiektów funkcjonalnych jako pierwszorzędnych obywateli. - John Leidegren
Nienawidzę rzeczy niestandardowych, zwłaszcza w językach programowania, dlaczego istnieje nawet proto kiedy to wyraźnie nie jest potrzebne? - John Leidegren
@ H1D: if Class.method nie zostanie znaleziony, szuka go środowisko wykonawcze Class.__proto__.method (albo raczej Object.getPrototypeOf(Class).method w zgodnym ES5) i nie  Class.prototype.method - Christoph
zauważ, że użycie [[Prototyp]] jest celowe - ECMA-262 zawiera nazwy właściwości wewnętrznych z podwójnymi nawiasami kwadratowymi - Christoph


W języku implementującym klasyczne dziedziczenie, takie jak Java, C # lub C ++, zaczynasz od utworzenia klasy - planu dla twoich obiektów - a następnie możesz tworzyć nowe obiekty z tej klasy lub możesz rozszerzyć klasę, definiując nową klasę, która rozszerza oryginalna klasa.

W JavaScript najpierw tworzysz obiekt (nie ma pojęcia klasy), możesz wtedy ulepszyć swój własny obiekt lub stworzyć z niego nowe obiekty. Nie jest to trudne, ale trochę obce i trudne do metabolizowania dla kogoś przyzwyczajonego do klasycznego sposobu.

Przykład:

//Define a functional object to hold persons in JavaScript
var Person = function(name) {
  this.name = name;
};

//Add dynamically to the already defined object a new getter
Person.prototype.getName = function() {
  return this.name;
};

//Create a new object of type Person
var john = new Person("John");

//Try the getter
alert(john.getName());

//If now I modify person, also John gets the updates
Person.prototype.sayMyName = function() {
  alert('Hello, my name is ' + this.getName());
};

//Call the new method on john
john.sayMyName();

Do tej pory rozszerzałem obiekt bazowy, teraz tworzę kolejny obiekt, a następnie dziedziczę po osobie.

//Create a new object of type Customer by defining its constructor. It's not 
//related to Person for now.
var Customer = function(name) {
    this.name = name;
};

//Now I link the objects and to do so, we link the prototype of Customer to 
//a new instance of Person. The prototype is the base that will be used to 
//construct all new instances and also, will modify dynamically all already 
//constructed objects because in JavaScript objects retain a pointer to the 
//prototype
Customer.prototype = new Person();     

//Now I can call the methods of Person on the Customer, let's try, first 
//I need to create a Customer.
var myCustomer = new Customer('Dream Inc.');
myCustomer.sayMyName();

//If I add new methods to Person, they will be added to Customer, but if I
//add new methods to Customer they won't be added to Person. Example:
Customer.prototype.setAmountDue = function(amountDue) {
    this.amountDue = amountDue;
};
Customer.prototype.getAmountDue = function() {
    return this.amountDue;
};

//Let's try:       
myCustomer.setAmountDue(2000);
alert(myCustomer.getAmountDue());

var Person = function (name) {
    this.name = name;
};
Person.prototype.getName = function () {
    return this.name;
};
var john = new Person("John");
alert(john.getName());
Person.prototype.sayMyName = function () {
    alert('Hello, my name is ' + this.getName());
};
john.sayMyName();
var Customer = function (name) {
    this.name = name;
};
Customer.prototype = new Person();

var myCustomer = new Customer('Dream Inc.');
myCustomer.sayMyName();
Customer.prototype.setAmountDue = function (amountDue) {
    this.amountDue = amountDue;
};
Customer.prototype.getAmountDue = function () {
    return this.amountDue;
};
myCustomer.setAmountDue(2000);
alert(myCustomer.getAmountDue());

Chociaż, jak powiedziałem, nie mogę wywołać setAmountDue (), getAmountDue () na osobę.

//The following statement generates an error.
john.setAmountDue(1000);

1755
2018-01-24 03:42



Myślę, że odpowiedzi na stackoverflow są nie tylko interesujące dla oryginalnego plakatu, ale także dla dużej społeczności innych ludzi czających się lub pochodzących z wyszukiwań. Byłem jednym z nich i korzystałem ze starych postów. Myślę, że mógłbym przyczynić się do innych odpowiedzi dodając przykłady kodu. O twoim pytaniu: jeśli zapomnisz o nowym, to nie działa. gdy wywołuję funkcję myCustomer.sayMyName (), zwraca ona "mójCustomer.sayMyName nie jest funkcją". Najprostszym sposobem jest eksperyment z firebugiem i zobaczenie, co się stanie. - stivlo
O ile rozumiem var Person = function (name) {...}; definiuje funkcję konstruktora zdolną do budowania Person Objects. Więc nie ma jeszcze obiektu, tylko anonimowa funkcja konstruktora jest przypisana do osoby. To jest bardzo dobre wytłumaczenie: helephant.com/2008/08/how-javascript-objects-work - stivlo
OSTRZEŻENIE: Ta odpowiedź nie uwzględnia faktu, że konstruktor klasy nadrzędnej nie jest wywoływany dla poszczególnych instancji. Jedyny powód, dla którego to działa, to fakt, że zrobił dokładnie to samo (ustawiając nazwę) zarówno w konstruktorze podrzędnym, jak i macierzystym. Aby uzyskać bardziej szczegółowe wyjaśnienie na temat typowych błędów popełnianych przy próbie dziedziczenia w JavaScript (i ostatecznym rozwiązaniu), zobacz: ten stos przepełnienia stosu - Aaren Cordova
Zauważyłem, że ta odpowiedź nie wspomina również, że używając "nowej osoby ()" jako prototypu, faktycznie ustawiasz właściwość "nazwa" instancji "Person", aby być statyczną własnością "klienta" (tak, że wszyscy klienci instancje będą miały tę samą właściwość). Chociaż jest to dobry podstawowy przykład, NIE ROBIĄ TO. :) Utwórz nową anonimową funkcję, która będzie działać jako "most", ustawiając prototyp na "Person.prototype", następnie stwórz z niego instancję i zamiast tego ustaw "Customer.prototype" na tę anonimową instancję. - James Wilkins
O Customer.prototype = new Person(); linia, MDN pokazuje przykład użycia Customer.prototype = Object.create(Person.prototype)i stwierdza, że "Najczęstszym błędem jest tutaj użycie" nowej osoby () "". źródło - Rafael Eyng


Odgrywam rolę nauczyciela JavaScript, a prototypowa koncepcja zawsze była kontrowersyjnym tematem do omówienia, kiedy nauczam. Zajęło mi trochę czasu wymyślenie dobrej metody wyjaśnienia tej koncepcji, a teraz w tym tekście będę próbować wyjaśnić, jak działa JavaScript .prototype.


Jest to bardzo prosty model obiektowy oparty na prototypach, który zostałby uznany za próbkę podczas wyjaśnienia, bez komentarza:

function Person(name){
    this.name = name;
}
Person.prototype.getName = function(){
    console.log(this.name);
}
var person = new Person("George");

Zanim przejdziemy do koncepcji prototypu, musimy wziąć pod uwagę kilka kluczowych punktów.

1- Jak faktycznie działają funkcje JavaScript:

Aby zrobić pierwszy krok, musimy dowiedzieć się, jak faktycznie działają funkcje JavaScript, używając klasowej funkcji this słowo kluczowe w nim lub zwykła funkcja z jego argumentami, co robi i co zwraca.

Powiedzmy, że chcemy stworzyć Person model obiektowy. ale w tym kroku będę próbować rób dokładnie to samo bez użycia prototype i new słowo kluczowe.

Tak więc na tym etapie functions, objects i this słowo kluczowe, wszystko co mamy.

Pierwsze pytanie byłoby w jaki sposób this słowo kluczowe może być przydatne bez użycia new słowo kluczowe.

Aby odpowiedzieć na to pytanie, powiedzmy, że mamy pusty obiekt i dwie funkcje, takie jak:

var person = {};
function Person(name){  this.name = name;  }

function getName(){
    console.log(this.name);
}

i teraz bez używania new słowo kluczowe jak możemy wykorzystać te funkcje. Więc JavaScript ma 3 różne sposoby na zrobienie tego:

za. Pierwszym sposobem jest po prostu wywołanie funkcji jako zwykłej funkcji:

Person("George");
getName();//would print the "George" in the console

w tym przypadku byłby to bieżący obiekt kontekstu, który zwykle jest globalny window obiekt w przeglądarce lub GLOBAL w Node.js. Oznacza to, że będziemy mieli, window.name w przeglądarce lub GLOBAL.name w Node.js, z "George" jako jego wartość.

b. Możemy dołączać ich do obiektu, jako jego właściwości

-Najprostszy sposób w tym celu modyfikujemy puste person obiekt, taki jak:

person.Person = Person;
person.getName = getName;

w ten sposób możemy je nazwać:

person.Person("George");
person.getName();// -->"George"

a teraz person Obiekt wygląda tak:

Object {Person: function, getName: function, name: "George"}

-Innym sposobem na dołączenie nieruchomości do obiektu korzysta z prototype tego obiektu, który można znaleźć w dowolnym obiekcie JavaScript o nazwie __proto__, i próbowałem wyjaśnić to nieco w części podsumowującej. Aby uzyskać podobny wynik, wykonaj:

person.__proto__.Person = Person;
person.__proto__.getName = getName;

Ale tak naprawdę to, co robimy, to modyfikowanie Object.prototype, ponieważ za każdym razem, gdy tworzymy obiekt JavaScript za pomocą literałów ({ ... }), tworzy się na podstawie Object.prototype, co oznacza, że ​​zostaje dołączony do nowo utworzonego obiektu jako atrybut o nazwie __proto__ , więc jeśli zmienimy to, tak jak to zrobiliśmy w naszym poprzednim fragmencie kodu, wszystkie obiekty JavaScript zostaną zmienione, a nie dobra praktyka. Więc jaka może być teraz lepsza praktyka:

person.__proto__ = {
    Person: Person,
    getName: getName
};

a teraz inne przedmioty są w spokoju, ale nadal nie wydaje się to dobrą praktyką. Mamy więc jeszcze jedno rozwiązanie, ale aby użyć tego rozwiązania, powinniśmy wrócić do tej linii kodu gdzie person obiekt został stworzony (var person = {};) następnie zmień go tak:

var propertiesObject = {
    Person: Person,
    getName: getName
};
var person = Object.create(propertiesObject);

to, co robi, to tworzenie nowego JavaScript Object i dołącz propertiesObject do __proto__ atrybut. Aby upewnić się, że możesz:

console.log(person.__proto__===propertiesObject); //true

Ale podstępną kwestią jest to, że masz dostęp do wszystkich właściwości zdefiniowanych w __proto__ na pierwszym poziomie person obiekt (przeczytaj część podsumowującą po więcej szczegółów).


jak widzisz, używając dowolnego z tych dwóch sposobów this dokładnie wskazuje na person obiekt.

do. JavaScript ma inny sposób na zapewnienie funkcji this, który jest używany połączenie lub zastosować aby wywołać funkcję.

Metoda apply () wywołuje funkcję o podanej wartości i   argumenty dostarczane jako tablica (lub obiekt tablicowy).

i

Metoda call () wywołuje funkcję o podanej wartości i   argumenty przedstawione indywidualnie.

w ten sposób, który jest moim ulubionym, możemy łatwo wywołać nasze funkcje takie jak:

Person.call(person, "George");

lub

//apply is more useful when params count is not fixed
Person.apply(person, ["George"]);

getName.call(person);   
getName.apply(person);

Te 3 metody są ważnymi wstępnymi krokami w celu wykrycia funkcjonalności .prototype.


2- W jaki sposób new słowo kluczowe działa?

to jest drugi krok do zrozumienia .prototype funkcjonalność.to jest to, czego używam do symulacji procesu:

function Person(name){  this.name = name;  }
my_person_prototype = { getName: function(){ console.log(this.name); } };

w tej części będę starał się podjąć wszystkie kroki, które JavaScript bierze, bez używania new słowo kluczowe i prototype, kiedy używasz new słowo kluczowe. więc kiedy to zrobimy new Person("George"), Person funkcja służy jako konstruktor, to właśnie robi JavaScript, jeden po drugim:

za. przede wszystkim tworzy pusty obiekt, w zasadzie pusty hash jak:

var newObject = {};

b. następnym krokiem, jaki wykonuje JavaScript dołączać wszystkie prototypy obiektów do nowo utworzonego obiektu

mamy my_person_prototype tutaj podobny do obiektu prototypowego.

for(var key in my_person_prototype){
    newObject[key] = my_person_prototype[key];
}

To nie jest sposób, w jaki JavaScript w rzeczywistości łączy właściwości zdefiniowane w prototypie. Rzeczywisty sposób jest związany z prototypową koncepcją łańcucha.


za. & b. Zamiast tych dwóch kroków możesz osiągnąć dokładnie taki sam wynik:

var newObject = Object.create(my_person_prototype);
//here you can check out the __proto__ attribute
console.log(newObject.__proto__ === my_person_prototype); //true
//and also check if you have access to your desired properties
console.log(typeof newObject.getName);//"function"

teraz możemy zadzwonić getName funkcjonować w naszym my_person_prototype:

newObject.getName();

do. następnie daje ten obiekt konstruktorowi,

możemy to zrobić z naszą próbką jak:

Person.call(newObject, "George");

lub

Person.apply(newObject, ["George"]);

wtedy konstruktor może zrobić, co chce, ponieważ to wewnątrz tego konstruktora jest właśnie utworzony obiekt.

teraz wynik końcowy przed symulacją pozostałych kroków:     Object {name: "George"}


Podsumowanie:

Zasadniczo, kiedy używasz Nowy słowo kluczowe w funkcji, wywołujesz to i ta funkcja służy jako konstruktor, więc kiedy mówisz:

new FunctionName()

JavaScript wewnętrznie tworzy obiekt, pusty hasz, a następnie przekazuje ten obiekt do konstruktora, a następnie konstruktor może zrobić, co chce, ponieważ to wewnątrz tego konstruktora jest obiekt, który właśnie został utworzony, 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 twojego ciała funkcyjnego.

Więc kiedy JavaScript idzie szukać właściwości obiektu, pierwszą rzeczą, którą robi, jest to, że wyszukuje go na tym obiekcie. A następnie istnieje tajemna własność [[prototype]] które zwykle mamy __proto__ a ta właściwość jest następną przeglądarką JavaScript. A kiedy patrzy przez __proto__, o ile jest to kolejny obiekt JavaScript, ma swój własny __proto__atrybut, idzie w górę iw górę, aż dojdzie do punktu, w którym następny __proto__ ma wartość null. Punkt jest jedynym obiektem w JavaScript, który jest jego __proto__ atrybut ma wartość null Object.prototype obiekt:

console.log(Object.prototype.__proto__===null);//true

i tak działa dziedziczenie w JavaScript.

The prototype chain

Innymi słowy, gdy masz prototypową właściwość dla funkcji i wywołujesz nową na tym, po tym jak JavaScript zakończy przeglądanie tego nowo utworzonego obiektu dla właściwości, przejrzysz jego funkcję .prototype a także jest możliwe, że obiekt ten ma swój własny wewnętrzny prototyp. i tak dalej.


163
2018-02-13 19:32



a) Proszę nie wyjaśniać prototypów przez kopiowanie właściwości b) Ustawianie wewnętrznego [[prototyp]] dzieje się, zanim funkcja konstruktora zostanie zastosowana na instancji, zmień tę kolejność c) jQuery jest całkowicie offtopic w tym pytaniu - Bergi
@Bergi: dzięki za wskazanie, byłbym wdzięczny, gdybyś dała mi znać, czy teraz jest OK. - Mehran Hatami
Czy możesz to uczynić prostym? Masz rację we wszystkich punktach, ale uczniowie, którzy czytają to wyjaśnienie, mogą być naprawdę zdezorientowani po raz pierwszy. weź prostszy przykład i pozwól, aby kod sam się wyjaśnił lub dodaj kilka komentarzy, aby wyjaśnić, co masz na myśli. - P.M
@ P.M: Dziękujemy za opinię. Starałem się uczynić to tak prostym, jak to tylko możliwe, ale myślę, że masz rację, wciąż ma pewne niejasne punkty. Spróbuję go zmodyfikować, a także będę bardziej opisowy. :) - Mehran Hatami
+1 dla ilustracji na końcu "książki" :) - sargas


prototype pozwala tworzyć zajęcia. jeśli nie używasz prototype to staje się statyczne.

Oto krótki przykład.

var obj = new Object();
obj.test = function() { alert('Hello?'); };

W powyższym przypadku masz statyczny test wywoływania funkcji. Ta funkcja może być dostępna tylko przez obj.test, gdzie możesz sobie wyobrazić, że obiekt jest klasą.

gdzie jak w poniższym kodzie

function obj()
{
}

obj.prototype.test = function() { alert('Hello?'); };
var obj2 = new obj();
obj2.test();

Obiekt stał się klasą, którą można teraz utworzyć. Może istnieć wiele instancji obiektu, a wszystkie one mają test funkcjonować.

Powyższe jest moim zrozumieniem. Robię to jako wiki społeczności, więc ludzie mogą mnie poprawić, jeśli się mylę.


66
2017-11-07 09:48



-1: prototype jest własnością funkcji konstruktora, a nie instancji, tzn. kod jest nieprawidłowy! Być może chodziło Ci o niestandardową własność __proto__ obiektów, ale to zupełnie inna bestia ... - Christoph
@Christoph - Dzięki za wskazanie. Zaktualizowałem przykładowy kod. - Ramesh
To rodzaj dobrej odpowiedzi, ale jest w tym coś więcej. - John Leidegren
Jest o wiele więcej ... Plus JavaScript nie jest językiem opartym na klasach - zajmuje się dziedziczeniem za pośrednictwem prototypów, musisz szczegółowo opisać różnice! - James
Myślę, że ta odpowiedź jest trochę myląca. - Armin Cifuentes


Po przeczytaniu tego wątku, czuję się zdezorientowany z JavaScript Prototype Chain, a następnie znalazłem te wykresy

http://iwiki.readthedocs.org/en/latest/javascript/js_core.html#inheritance *[[protytype]]* and <code>prototype</code> property of function objects

jasny wykres pokazujący dziedziczenie JavaScript według łańcucha prototypów

i

http://www.javascriptbank.com/javascript/article/JavaScript_Classical_Inheritance/

ten zawiera przykład z kodem i kilkoma ładnymi diagramami.

łańcuch prototypów ostatecznie wraca do Object.prototype.

Łańcuch prototypowy może być technicznie przedłużany tak długo, jak chcesz, za każdym razem ustawiając prototyp podklasy na równy obiektowi klasy nadrzędnej.

Mam nadzieję, że pomocne jest zrozumienie łańcucha prototypów JavaScript.


59
2018-05-26 20:40



Byłoby wspaniale, gdybyś mógł podać krótkie streszczenie zawartości linków, więc ta odpowiedź jest nadal przydatna, gdy linki są martwe. - Nicktar
@Nicktar, Dzięki za sugestię, dodałem prosty opis tych linków. - rockXrock
to wyraźny wykres? :) - Nuno_147
Schemat mówi tysiąc słów. Jest to bardzo przydatne :) - Mark Robson
Czy możesz wyjaśnić co? [[Prototype]] znaczy? - CodyBugstein


Siedem Koanów prototypu

Kiedy Ciro San zstąpił z 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 zapisała następujące notatki.


0) Dwie różne rzeczy można nazwać "prototypowymi":

  • prototypowa właściwość, jak w obj.prototype

  • prototypowa własność wewnętrzna, oznaczona jako [[Prototype]]  w ES5.

    Można go pobrać przez ES5 Object.getPrototypeOf().

    Firefox udostępnia ją przez __proto__ właściwość jako rozszerzenie. ES6 teraz wspomina niektóre opcjonalne wymagania dla __proto__.


1) Te koncepcje istnieją, aby odpowiedzieć na pytanie:

Kiedy robię obj.property, gdzie szuka JS .property?

Intuicyjnie dziedziczenie klasyczne powinno wpływać na wyszukiwanie właściwości.


2)

  • __proto__ jest używany dla kropki . wyszukiwanie właściwości jak w obj.property.
  • .prototype jest nie używane do bezpośredniego wyszukiwania, tylko pośrednio, jak to określa __proto__ przy tworzeniu obiektu przy pomocy new.

Kolejność wyszukiwania to:

  • obj właściwości dodane z obj.p = ... lub Object.defineProperty(obj, ...)
  • właściwości obj.__proto__
  • właściwości obj.__proto__.__proto__, i tak dalej
  • Jeśli niektóre __proto__ jest null, powrót undefined.

To jest tzw prototypowy łańcuch.

Możesz tego uniknąć . wyszukiwanie przy pomocy obj.hasOwnProperty('key') i Object.getOwnPropertyNames(f)


3) Istnieją dwa główne sposoby ustawiania obj.__proto__:

  • new:

    var F = function() {}
    var f = new F()
    

    następnie new ustawił:

    f.__proto__ === F.prototype
    

    To gdzie jest .prototype zostaje wykorzystany.

  • Object.create:

     f = Object.create(proto)
    

    zestawy:

    f.__proto__ === proto
    

4) Kod:

var F = function() {}
var f = new F()

Odpowiada poniższemu diagramowi:

(Function)       (  F  )                                      (f)
 |  ^             | | ^                                        |
 |  |             | | |                                        |
 |  |             | | +-------------------------+              |
 |  |constructor  | |                           |              |
 |  |             | +--------------+            |              |
 |  |             |                |            |              |
 |  |             |                |            |              |
 |[[Prototype]]   |[[Prototype]]   |prototype   |constructor   |[[Prototype]]
 |  |             |                |            |              |
 |  |             |                |            |              |
 |  |             |                | +----------+              |
 |  |             |                | |                         |
 |  |             |                | | +-----------------------+
 |  |             |                | | |
 v  |             v                v | v
(Function.prototype)              (F.prototype)
 |                                 |
 |                                 |
 |[[Prototype]]                    |[[Prototype]]
 |                                 |
 |                                 |
 | +-------------------------------+
 | |
 v v
(Object.prototype)
 | | ^
 | | |
 | | +---------------------------+
 | |                             |
 | +--------------+              |
 |                |              |
 |                |              |
 |[[Prototype]]   |constructor   |prototype
 |                |              |
 |                |              |
 |                | -------------+
 |                | |
 v                v |
(null)           (Object)

Ten diagram pokazuje wiele predefiniowanych języków obiektu węzłów: null, Object, Object.prototype, Function i Function.prototype. Nasze 2 linie kodu zostały utworzone f, F i F.prototype.


5)  .constructor zwykle pochodzi z F.prototype przez . wyszukiwanie:

f.constructor === F
!f.hasOwnProperty('constructor')
Object.getPrototypeOf(f) === F.prototype
F.prototype.hasOwnProperty('constructor')
F.prototype.constructor === f.constructor

Kiedy piszemy f.constructor, JavaScript robi . wyszukiwanie jako:

  • f nie ma .constructor
  • f.__proto__ === F.prototype ma .constructor === F, więc weź to

Wynik f.constructor == F jest intuicyjnie poprawny, ponieważ F służy do konstruowania f, np. ustawić pola, podobnie jak w klasycznych językach OOP.


6) Klasyczna składnia dziedziczenia może zostać osiągnięta poprzez manipulowanie łańcuchami prototypów.

ES6 dodaje class i extends słowa kluczowe, które są po prostu cukrem składniowym dla wcześniejszego możliwego prototypowego szaleństwa manipulacji.

class C {
    constructor(i) {
        this.i = i
    }
    inc() {
        return this.i + 1
    }
}

class D extends C {
    constructor(i) {
        super(i)
    }
    inc2() {
        return this.i + 2
    }
}
// Inheritance syntax works as expected.
(new C(1)).inc() === 2
(new D(1)).inc() === 2
(new D(1)).inc2() === 3
// "Classes" are just function objects.
C.constructor === Function
C.__proto__ === Function.prototype
D.constructor === Function
// D is a function "indirectly" through the chain.
D.__proto__ === C
D.__proto__.__proto__ === Function.prototype
// "extends" sets up the prototype chain so that base class
// lookups will work as expected
var d = new D(1)
d.__proto__ === D.prototype
D.prototype.__proto__ === C.prototype
// This is what `d.inc` actually does.
d.__proto__.__proto__.inc === C.prototype.inc
// Class variables
// No ES6 syntax sugar apparently:
// http://stackoverflow.com/questions/22528967/es6-class-variable-alternatives
C.c = 1
C.c === 1
// Because `D.__proto__ === C`.
D.c === 1
// Nothing makes this work.
d.c === undefined

Uproszczony schemat bez wszystkich predefiniowanych obiektów:

      __proto__
(C)<---------------(D)         (d)
| |                |           |
| |                |           |
| |prototype       |prototype  |__proto__
| |                |           |
| |                |           |
| |                | +---------+
| |                | |
| |                | |
| |                v v
|__proto__        (D.prototype)
| |                |
| |                |
| |                |__proto__
| |                |
| |                |
| | +--------------+
| | |
| | |
| v v
| (C.prototype)--->(inc)
|
v
Function.prototype

57
2018-06-18 19:48



Nie wiem, skąd to masz, ale to jest najbardziej jasna odpowiedź! - tomasb
@tomasb dzięki! "Nie wiem, skąd masz to": po tym, jak zobaczyłem kilka z tych dynamicznych języków, zauważyłem, że najważniejsze w ich systemie klasowym jest to, w jaki sposób . działa odnośnik (i ile kopii danych jest tworzonych). Więc postanowiłem zrozumieć ten punkt. Reszta to blogi Google + i interpreter Js pod ręką. :) - Ciro Santilli 新疆改造中心 六四事件 法轮功
Ta odpowiedź pokazuje prawdziwe i głębokie zrozumienie tej koncepcji. Dobra robota! - Nir Smadar
Wciąż nie rozumiem, dlaczego g.constructor === Obiekt, ponieważ powiedziałeś, że "4) Kiedy robisz f = new F, new również ustawia f.constructor = F". Czy mógłbyś mi więcej wytłumaczyć? W każdym razie jest to najlepsza odpowiedź, której szukam. Dziękuję bardzo! - nguyenngoc101
@ Teraz wszystko jasne, głosowałem za twoją odpowiedzią. Dziękuję za pomoc. - nguyenngoc101


Każdy obiekt ma własność wewnętrzną, [[Prototyp]], łącząc go z innym obiektem:

object [[Prototype]] -> anotherObject

W tradycyjnym javascriptu połączonym obiektem jest prototype właściwość funkcji:

object [[Prototype]] -> aFunction.prototype

Niektóre środowiska narażają [[Prototype]] jako __proto__:

anObject.__proto__ === anotherObject

Tworzysz łącze [[Prototyp]] podczas tworzenia obiektu.

// (1) Object.create:
var object = Object.create(anotherObject)
// object.__proto__ = anotherObject

// (2) ES6 object initializer:
var object = { __proto__: anotherObject };
// object.__proto__ = anotherObject

// (3) Traditional JavaScript:
var object = new aFunction;
// object.__proto__ = aFunction.prototype

Tak więc te stwierdzenia są równoważne:

var object = Object.create(Object.prototype);
var object = { __proto__: Object.prototype }; // ES6 only
var object = new Object;

ZA new oświadczenie nie pokazuje celu linku (Object.prototype) samo; zamiast tego cel jest implikowany przez konstruktora (Object).

Zapamiętaj:

  • Każdy obiekt ma link, [[Prototyp]], czasem wystawiony jako __proto__.
  • Każda funkcja ma prototype własność.
  • Obiekty utworzone za pomocą new są powiązane z prototype własność ich konstruktora.
  • Jeśli funkcja nie jest nigdy używana jako konstruktor, jej prototype nieruchomość zostanie wykorzystana.
  • Jeśli nie potrzebujesz konstruktora, użyj Object.create zamiast new.

33
2018-02-21 12:41



+1 do podświetlania Object.create () - Jakob Sternberg
W wersji 5 usunięto kilka przydatnych informacji, w tym informacje o Object.create (). Widzieć wersja 4. - Palec
@Palec co powinienem dodać? - sam
IMO przynajmniej link do Object.create() docs, @sam. Linki do __proto__ i Object.prototype byłoby miłym dodatkiem. I podobają mi się twoje przykłady tego, jak prototypy pracują z konstruktorami i Object.create(), ale prawdopodobnie były to długie i mniej istotne części, których chciałeś się pozbyć. - Palec
z całej dyskusji, co otrzymuję (pochodzi z dziedziczenia klasycznego), jeśli utworzę funkcję konstruktora i spróbuję utworzyć jej instancję za pomocą nowego operatora, otrzymam tylko metody i właściwości, które zostały dołączone do obiektu proto, dlatego konieczne jest dołączenie całej metody i właściwości obiektu proto, jeśli chcemy dziedziczyć, mam rację? - blackHawk


JavaScript nie ma dziedziczenia w zwykłym znaczeniu, ale ma łańcuch prototypów.

prototypowy łańcuch

Jeśli nie można znaleźć obiektu obiektu w obiekcie, szuka go w łańcuchu prototypów. Łańcuch składa się z innych obiektów. Prototyp danej instancji można uzyskać za pomocą __proto__ zmienna. 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 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.


23
2017-11-04 14:08



Obsługa FF i Chrome proto, ale nie IE ani Opera. - some
Georg, proszę, wyjaśnij noobowi - "nie ma różnicy między klasami i instancjami w javascript." - Czy mógłbyś rozwinąć? Jak to działa? - Hamish Grubijan
z całej dyskusji, co otrzymuję (pochodzi z dziedziczenia klasycznego), jeśli utworzę funkcję konstruktora i spróbuję utworzyć jej instancję za pomocą nowego operatora, otrzymam tylko metody i właściwości, które zostały dołączone do obiektu proto, dlatego konieczne jest dołączenie całej metody i właściwości obiektu proto, jeśli chcemy dziedziczyć, mam rację? - blackHawk