Jak działa JavaScript.prace nad prototypem?

Nie przepadam za dynamicznymi językami programowania, ale napisałem sporo kodu JavaScript. Nigdy nie miałem głowy do tego programowania opartego 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 z ludźmi jakiś czas temu (nie jestem dokładnie pewien, co robię) , ale jak rozumiem, nie ma pojęcia o klasie. To tylko obiekt, a instancje tych obiektów są klonami oryginału, prawda?

Ale co to jest dokładny cel tego ".prototype " właściwość w JavaScript? Jak to się ma do tworzenia instancji obiektów?

Update: correct way

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

Również te slajdy naprawdę bardzo pomogły.

Author: John Leidegren, 2009-02-21

23 answers

Każdy obiekt JavaScript ma wewnętrzną właściwość o nazwie [[Prototype]] . Jeśli wyszukujesz właściwość za pomocą obj.propName lub obj['propName'] i Obiekt nie posiada takiej właściwości - którą można sprawdzić za pomocą obj.hasOwnProperty('propName') - runtime wyszukuje właściwość w obiekcie, do którego odnosi się [[Prototype]]. Jeśli prototype-object również nie ma takiej właściwości, jego prototyp jest sprawdzany z kolei, a więc chodzi prototype-chain aż do znalezienia dopasowania lub jego końca / align = "left" /

Niektóre implementacje JavaScript umożliwiają bezpośredni dostęp do właściwości [[Prototype]], np. poprzez niestandardową właściwość o nazwie __proto__. Ogólnie rzecz biorąc, można ustawić prototyp obiektu tylko podczas tworzenia obiektu: jeśli utworzysz nowy obiekt za pomocą new Func(), właściwość [[Prototype]] zostanie ustawiona na obiekt, do którego odnosi się Func.prototype.

Pozwala to symulować klasy w JavaScript, chociaż system dziedziczenia JavaScript jest - jak widzieliśmy-prototypowy, a nie "class-based": {]}

Pomyśl tylko o funkcjach konstruktora jako klasach, a właściwości prototypu (tj. obiektu, do którego odwołuje się właściwość funkcji konstruktora prototype) jako współdzielonych członach, tj. członach, które są takie same dla każdej instancji. W systemach opartych na klasach 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, a zatem dodawane do samego obiektu podczas budowy.

 941
Author: Christoph,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-27 13:23:22

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 tworzyć nowe obiekty z tej klasy lub możesz rozszerzyć klasę, definiując nową klasę, która rozszerza oryginalną klasę.

W JavaScript najpierw tworzysz obiekt (nie ma pojęcia o klasie), potem możesz powiększać swój własny obiekt lub tworzyć z niego nowe obiekty. To nie jest trudne, ale trochę obce i trudne do metabolizmu dla ktoś przywykł do klasycznego stylu.

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 podstawowy, 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());

Podczas gdy nie mogę wywołać setAmountDue (), getAmountDue () na osobie.

//The following statement generates an error.
john.setAmountDue(1000);
 1764
Author: stivlo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-02 15:03:08

gram rolę nauczyciela JavaScript, a koncepcja prototypu zawsze była kontrowersyjnym tematem, gdy nauczam. Zajęło mi trochę czasu, aby wymyślić dobrą metodę wyjaśnienia pojęcia, a teraz w tym tekście będę starał się wyjaśnić, jak JavaScript .prace nad prototypem.


Jest to bardzo prosty model obiektowy oparty na prototypie, który byłby uważany za próbkę podczas wyjaśnienia, Bez komentarza jeszcze:

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

Są kilka kluczowych kwestii, które musimy rozważyć przed przejściem do koncepcji prototypu.

1 - Jak działają funkcje JavaScript:

Aby zrobić pierwszy krok musimy dowiedzieć się, jak funkcje JavaScript faktycznie działają, jako funkcja podobna do klasy za pomocą this słowo kluczowe w nim lub po prostu jako 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ł zrób dokładnie to samo bez użycia prototype i new słowa kluczowego .

Więc w tym kroku functions, objects oraz this słowo kluczowe, to wszystko, co mamy.

Pierwsze pytanie brzmi jak this słowo kluczowe może być przydatne bez użycia new słowa kluczowego .

Aby odpowiedzieć, powiedzmy, że mamy pusty obiekt i dwie funkcje, takie jak:]}

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

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

A teraz bez użycia new słowa kluczowego jak moglibyśmy użyć tych funkcje. Tak więc JavaScript ma 3 różne sposoby, aby to zrobić:

A. pierwszym sposobem jest wywołanie funkcji jako funkcji regularnej:

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

W tym przypadku będzie to bieżący obiekt kontekstowy, który zwykle jest globalnym obiektem window w przeglądarce lub GLOBAL w Node.js. To znaczy, że mielibyśmy, window.name w przeglądarce lub GLOBAL.name w węźle.js, z "George" jako jego wartość.

B. możemy dołączyć je do obiektu, jako jego właściwości

-najprostszym sposobem jest zmodyfikowanie pustego obiektu person, jak:

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

W ten sposób możemy je nazywać tak:

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

A teraz person obiekt wygląda następująco:

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

-innym sposobem na dołączenie 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. Więc możemy uzyskać podobny wynik robiąc:

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

Ale w ten sposób to, co faktycznie robimy, to modyfikowanie Object.prototype, ponieważ za każdym razem, gdy tworzymy obiekt JavaScript za pomocą literałów ({ ... }), jest on tworzony na podstawie Object.prototype , co oznacza, że jest dołączany do nowo utworzonego obiektu jako atrybut o nazwie __proto__ , jeśli więc go zmienimy, tak jak to zrobiliśmy w poprzednim fragmencie kodu, wszystkie obiekty JavaScript zostaną zmienione, nie jest to dobra praktyka. Więc co może być lepszą praktyką teraz:

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

I teraz inne obiekty są w pokoju, ale nadal nie wydaje się to być dobrą praktyką. Mamy więc jeszcze jedno rozwiązanie, ale aby skorzystać z tego rozwiązania, powinniśmy wrócić do linii kodu, w której person został utworzony obiekt (var person = {};), a następnie zmienić go w następujący sposób:

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

Tworzy nowy JavaScript Object i dołącza {[45] } do atrybutu __proto__. Więc aby upewnić się, że możesz zrobić:

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

Ale najtrudniejszym punktem tutaj jest to, że masz dostęp do wszystkich właściwości zdefiniowane w __proto__ na pierwszym poziomie obiektu person (więcej szczegółów w części podsumowującej).


Jak widzisz, użycie któregokolwiek z tych dwóch sposobów this dokładnie wskazywałoby obiekt person.

C. JavaScript ma inny sposób dostarczenia funkcji za pomocą this, który polega na użyciu calllub apply do wywołania funkcji.

Metoda apply() wywołuje funkcję o podanej tej wartości i argumenty podane jako tablica (lub obiekt podobny do tablicy).

I

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

W ten sposób, który jest moim ulubionym, możemy łatwo nazwać nasze funkcje 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 początkowymi krokami, aby dowiedzieć się.funkcjonalność prototypu.


2-Jak działa słowo kluczowe new?

Jest to drugi krok do zrozumieć funkcjonalność .prototype.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ę wykonać wszystkie kroki, które wykonuje JavaScript, bez użycia słowa kluczowego new i prototype, gdy używasz słowa kluczowego new. więc kiedy robimy new Person("George"), Person funkcja służy jako konstruktor, to jest to, co robi JavaScript, jeden po drugim:

A. przede wszystkim tworzy pusty obiekt, w zasadzie pusty hash w stylu:

var newObject = {};

B. następny krok, który JavaScript wymaga, aby dołączyć wszystkie prototypowe obiekty do nowo utworzonego obiektu

Mamy tutaj my_person_prototype podobny do prototypowego obiektu.

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

To nie jest sposób, w jaki JavaScript faktycznie dołącza właściwości zdefiniowane w prototypie. Rzeczywisty sposób jest związany z koncepcją łańcucha prototypowego.


A. & b. zamiast tych dwóch kroków możesz uzyskać dokładnie ten sam wynik, wykonując:

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 nazwać getName funkcja w naszym my_person_prototype:

newObject.getName();

C. 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 robić co chce, ponieważten {85]} wewnątrz tego konstruktora znajduje się obiekt, który właśnie został utworzony.

Teraz wynik końcowy przed symulacją pozostałych kroków: Obiekt {nazwa: "George"}


Podsumowanie:

Zasadniczo, gdy używasz nowe 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 hash, a następnie daje ten obiekt konstruktorowi, wtedy konstruktor może robić, co chce, ponieważ ten wewnątrz tego konstruktora jest obiekt, który został właśnie utworzony, a następnie daje ten obiekt oczywiście, jeśli nie użyłeś instrukcji return w swojej funkcji lub jeśli nie używałeś instrukcji return w swojej funkcji. umieść return undefined; na końcu swojego ciała funkcyjnego.

Więc kiedy JavaScript szuka właściwości obiektu, pierwszą rzeczą, którą robi, jest to, że szuka go na tym obiekcie. A potem jest tajna własność [[prototype]] które zwykle mamy jak __proto__ i ta właściwość jest tym, na co JavaScript patrzy dalej. A gdy spojrzy przez __proto__, o ile jest to kolejny obiekt JavaScript, ma swój własny __proto__ / align = "left" / aż dojdzie do punktu, w którym następny __proto__ jest null. Punkt jest jedynym obiektem w JavaScript, który jego __proto__ atrybut jest null jest Object.prototype obiekt:

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

I tak działa dziedziczenie w JavaScript.

Łańcuch prototypów

Innymi słowy, gdy masz właściwość prototypu funkcji i wywołasz nową na niej, po tym, jak JavaScript skończy patrzeć na nowo utworzony obiekt dla właściwości, przejdzie do funkcji .prototype i możliwe jest również, że obiekt ten posiada własny wewnętrzny prototyp. i tak dalej.

 166
Author: Mehran Hatami,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-07 15:16:00

prototype pozwala na prowadzenie zajęć. jeśli nie użyjesz prototype, stanie się to statyczne.

Oto krótki przykład.

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

W powyższym przypadku masz statyczny test wywołania funkcji. Dostęp do tej funkcji może uzyskać tylko obj.test, w którym można sobie wyobrazić obj jako klasę.

Gdzie jak w poniższym kodzie

function obj()
{
}

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

Obj stał się klasą, którą można teraz utworzyć. Może istnieć wiele instancji obj i wszystkie mają funkcję test.

Powyżej Tak rozumiem. Robię z tego wiki społeczność, więc ludzie mogą mnie poprawić, jeśli się mylę.

 70
Author: Ramesh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-21 13:51:26

Po przeczytaniu tego wątku, czuję się zmieszany z łańcuchem prototypów JavaScript, wtedy znalazłem te wykresy

Http://iwiki.readthedocs.org/en/latest/javascript/js_core.html#inheritance * [[protytype]] * i właściwości prototype obiektów funkcyjnych

jest to przejrzysty wykres pokazujący dziedziczenie JavaScript przez Prototype Chain

I

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

ten zawiera przykład z kodem i kilka fajnych diagramy.

Prototyp łańcucha ostatecznie spada z powrotem do obiektu.prototyp.

Prototype chain może być technicznie rozszerzony tak długo, jak chcesz, za każdym razem ustawiając prototyp podklasy równy obiektowi klasy nadrzędnej.

Mam nadzieję, że jest to również pomocne dla ciebie, aby zrozumieć JavaScript Prototype Chain.

 62
Author: rockXrock,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-09-27 01:33:12

Siedem Koanów prototypu

Kiedy Ciro San zszedł na górę ognistego Lisa po głębokiej medytacji, jego umysł był jasny i spokojny. Jego ręka była jednak niespokojna i sama chwyciła za pędzel i zapisała następujące nuty.

0) dwie różne rzeczy można nazwać "prototypem": {]}

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

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

    Można go pobrać za pomocą ES5 Object.getPrototypeOf().

    Firefox udostępnia go poprzez właściwość __proto__ jako rozszerzenie. ES6 wymienia teraz niektóre opcjonalne wymagania dla __proto__.


1) te pojęcia istnieją, aby odpowiedzieć na pytanie:

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

Intuicyjnie Klasyczne dziedziczenie powinno wpływać na własność / align = "left" /


2)

  • __proto__ jest używany do wyszukiwania właściwości dot . jak w obj.property.
  • .prototype jest Nie używane 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 przez obj.p = ... lub Object.defineProperty(obj, ...)
  • właściwości obj.__proto__
  • właściwości obj.__proto__.__proto__ i tak dalej
  • jeśli jakieś __proto__ jest null, zwróć undefined.

Jest to tzw. łańcuch prototypów.

Można uniknąć . wyszukiwania za pomocą obj.hasOwnProperty('key') i Object.getOwnPropertyNames(f)


3) istnieją dwa główne sposoby ustawienia obj.__proto__:

  • new:

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

    Wtedy new ustawia:

    f.__proto__ === F.prototype
    

    to {[114] } jest miejsce, gdzie .prototype jest używany.

  • Object.create:

     f = Object.create(proto)
    

    Zestawy:

    f.__proto__ === proto
    

4) na kod:

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

Odpowiada Następującemu schematowi:

(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 węzłów obiektów języka: null, Object, Object.prototype, Function i Function.prototype. Nasze 2 linie kodu tylko utworzone f, F i F.prototype.


5) .constructor zwykle pochodzi z F.prototype poprzez . lookup:

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 . lookup 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 jest używany do konstruowania f, np. pól set, podobnie jak w klasycznych językach OOP.


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

ES6 dodaje słowa kluczowe class i extends, które są po prostu cukrem składni do wcześniej możliwej manipulacji prototypami szaleństwo.

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
 61
Author: Ciro Santilli 新疆改造中心 六四事件 法轮功,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-08 06:31:36

Każdy obiekt ma wewnętrzną właściwość [[prototyp]], łącząc ją z innym obiektem:

object [[Prototype]] -> anotherObject

W tradycyjnym javascript, obiekt linkowany jest właściwością prototype funkcji:

object [[Prototype]] -> aFunction.prototype

Niektóre środowiska wystawiają [[prototyp]] jako __proto__:

anObject.__proto__ === anotherObject

Tworzysz łącze [[Prototype]] 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

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;

A new nie pokazuje samego celu linku (Object.prototype); zamiast tego cel jest implikowany przez konstruktor (Object).

Zapamiętaj:

  • każdy obiekt ma łącze, [[prototyp]], czasem wystawione jako __proto__.
  • każda funkcja ma właściwość prototype.
  • obiekty utworzone za pomocą new są powiązane z właściwością prototype ich konstruktora.
  • jeśli funkcja nigdy nie będzie używana jako konstruktor, jej właściwość prototype będzie nieużywana.
  • jeśli nie potrzebujesz konstruktora, użyj Object.Utwórz zamiast new.
 35
Author: sam,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-18 19:32:32

Javascript nie ma dziedziczenia w zwykłym sensie, ale ma łańcuch prototypów.

Prototype chain

Jeśli element obiektu nie może zostać znaleziony w obiekcie, szuka go w łańcuchu prototypów. Łańcuch składa się z innych obiektów. Do prototypu danej instancji można uzyskać dostęp za pomocą zmiennej __proto__. Każdy obiekt ma taki, ponieważ nie ma różnicy między klasami a instancjami w javascript.

Zaletą dodawania funkcji / zmiennej do prototyp polega na tym, że musi być w pamięci tylko raz, nie dla każdej instancji.

Jest to również przydatne do dziedziczenia, ponieważ łańcuch prototypów może składać się z wielu innych obiektów.

 24
Author: Georg Schölly,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-21 12:41:31

Ten artykuł jest długi. Ale jestem pewien, że to wyczyści większość zapytań w odniesieniu do "prototypowego" charakteru dziedziczenia JavaScript. I jeszcze więcej. Przeczytaj cały artykuł.

JavaScript zasadniczo ma dwa rodzaje typów danych

  • Non objects
  • Obiekty

Non objects

Poniżej znajdują się Non object dane typy

  • string
  • liczba (w tym NaN i Nieskończoność)
  • wartości logiczne (true, false)
  • undefined

Te typy danych zwracają się po użyciu operatora typeof

Typeof "string literal" (lub zmienna zawierająca string literal) === 'string"

Typeof 5 (lub dowolny literał liczbowy lub zmienna zawierająca literał liczbowy lub NaN lub Infinity) === 'numer"

Typeof true (lub false lub zmienna zawierająca true lub false) === 'boolean"

Typeof undefined (lub Niezdefiniowana zmienna lub zmienna zawierająca undefined) === 'undefined"

The string,numer oraz typy danych boolean mogą być reprezentowane zarówno jako Obiekty, jak i inne obiekty.Gdy są one reprezentowane jako obiekty, ich typeof jest zawsze = = = 'object'. Wrócimy do tego, gdy zrozumiemy typy danych obiektowych.

Obiekty

Typy danych obiektów można dalej podzielić na dwa typy

  1. obiekty typu Function
  2. obiekty typu Non Function

The obiekty typu Function są tymi, które zwracają łańcuch 'function' z operatorem typeof. Do tej kategorii należą wszystkie funkcje zdefiniowane przez użytkownika i wszystkie JavaScript wbudowane w obiekty, które mogą tworzyć nowe obiekty za pomocą nowego operatora. Dla np.

  • obiekt
  • String
  • numer
  • Boolean
  • Array
  • Typed Tablice
  • RegExp
  • funkcja
  • wszystkie inne wbudowane obiekty, które mogą tworzyć nowe obiekty za pomocą operatora new
  • funkcja UserDefinedFunction(){ /*kod zdefiniowany przez użytkownika*/}

Więc, typeof(Object) === typeof(String) === typeof(liczba) === typeof(Boolean) === typeof(Array) === typeof(RegExp) === typeof (Function) === typeof(UserDefinedFunction) === 'function"

Wszystkie obiekty typu Function w rzeczywistości są instancjami wbudowanego w JavaScript obiektu Function (łącznie z obiektem Function tzn. jest on definiowany rekurencyjnie). To tak, jakby te obiekty zostały zdefiniowane w następujący sposób

var Object= new Function ([native code for object Object])
var String= new Function ([native code for object String])
var Number= new Function ([native code for object Number])
var Boolean= new Function ([native code for object Boolean])
var Array= new Function ([native code for object Array])
var RegExp= new Function ([native code for object RegExp])
var Function= new Function ([native code  for object Function])
var UserDefinedFunction= new Function ("user defined code")

Jak wspomniano, obiekty typu Function może dalej tworzyć nowe obiekty za pomocą nowego operatora . Dla np. obiektu typu Object, String, numer, Boolean, Array, RegExp lub UserDefinedFunction można utworzyć za pomocą

var a=new Object() or var a=Object() or var a={} //Create object of type Object
var a=new String() //Create object of type String
var a=new Number() //Create object of type Number
var a=new Boolean() //Create object of type Boolean
var a=new Array() or var a=Array() or var a=[]  //Create object of type Array
var a=new RegExp() or var a=RegExp() //Create object of type RegExp
var a=new UserDefinedFunction() 

Tak stworzone obiekty to wszystkie obiekty typu Non Function i zwracają typeof==='obiekt" . We wszystkich tych przypadkach obiekt "a" nie może dalej tworzyć obiekty korzystające z operatora new. Więc poniższe jest błędne

var b=new a() //error. a is not typeof==='function'

Wbudowany obiekt Matematyka jest typeof==='obiekt" . W związku z tym nowy obiekt typu Math nie może być utworzony przez nowy operator.

var b=new Math() //error. Math is not typeof==='function'

Zauważ również, że obiekt,funkcje Array i RegExp mogą tworzyć nowy obiekt nawet bez użycia operatora new . Jednak te following Nie.

var a=String() // Create a new Non Object string. returns a typeof==='string' 
var a=Number() // Create a new Non Object Number. returns a typeof==='number'
var a=Boolean() //Create a new Non Object Boolean. returns a typeof==='boolean'

Funkcje zdefiniowane przez użytkownika są szczególnym przypadkiem.

var a=UserDefinedFunction() //may or may not create an object of type UserDefinedFunction() based on how it is defined.

Od na obiekty typu Function można tworzyć nowe obiekty nazywane również konstruktorzy.

Każdy Konstruktor/funkcja (niezależnie od tego, czy jest wbudowany, czy zdefiniowany przez użytkownika), gdy jest zdefiniowany automatycznie, ma właściwość o nazwie "prototype", której wartość domyślnie jest ustawiona jako obiekt. Ten obiekt posiada właściwość "constructor" , która domyślnie odwołuje się do Constructor/Function .

Dla przykład gdy definiujemy funkcję

function UserDefinedFunction()
{
}

Następuje automatycznie

UserDefinedFunction.prototype={constructor:UserDefinedFunction}

Ta właściwość"prototype" jest obecna tylko w obiektach typu funkcji (i nigdy w obiektach typu non Function ).

Dzieje się tak dlatego, że gdy tworzony jest nowy obiekt (używając nowego operatora), dziedziczy on wszystkie właściwości i metody z bieżącego prototypowego obiektu funkcji konstruktora, tj. numer wewnętrzny na utworzony w nowo utworzonym obiekcie, który odwołuje się do obiektu, do którego odwołuje się bieżący obiekt prototypowy funkcji konstruktora.

Ta "Wewnętrzna Referencja", która jest tworzona w obiekcie do odwoływania się do odziedziczonych właściwości, jest znana jako prototyp obiektu (który odwołuje się do obiektu wskazanego przez właściwość "prototype", ale różni się od niej). Dla dowolnego obiektu (funkcji lub nie funkcji) można to pobrać za pomocą obiekt.metoda getprototype () . Za pomocą tej metody można prześledzić łańcuch prototypów obiektu.

Również każdy obiekt, który jest tworzony (Function type lub Non Function type) ma właściwość "constructor" , która jest dziedziczona z obiektu, do którego odnosi się właściwość prototypu funkcji konstruktora. Domyślnie ta właściwość "constructor" odwołuje się do funkcji Constructor , która ją utworzyła (jeśli funkcja konstruktora domyślnie "prototyp" nie jest zmieniana).

Dla wszystkich obiekty typu Function funkcja konstruktora jest zawsze funkcja Funkcja(){}

Dla obiekty typu Non Function (np. Javascript wbudowany w obiekt matematyczny) funkcją konstruktora jest funkcja, która ją utworzyła. Dla matematyki obiekt jest obiekt funkcji(){}.

Cała koncepcja wyjaśnione powyżej może być nieco zniechęcające do zrozumienia bez żadnego kodu wspierającego. Proszę przejść przez poniższy kod wiersz po linii, aby zrozumieć tę koncepcję. Spróbuj go wykonać, aby lepiej zrozumieć.

function UserDefinedFunction()
{ 

} 

/* creating the above function automatically does the following as mentioned earlier

UserDefinedFunction.prototype={constructor:UserDefinedFunction}

*/


var newObj_1=new UserDefinedFunction()

alert(Object.getPrototypeOf(newObj_1)===UserDefinedFunction.prototype)  //Displays true

alert(newObj_1.constructor) //Displays function UserDefinedFunction

//Create a new property in UserDefinedFunction.prototype object

UserDefinedFunction.prototype.TestProperty="test"

alert(newObj_1.TestProperty) //Displays "test"

alert(Object.getPrototypeOf(newObj_1).TestProperty)// Displays "test"

//Create a new Object

var objA = {
        property1 : "Property1",
        constructor:Array

}


//assign a new object to UserDefinedFunction.prototype
UserDefinedFunction.prototype=objA

alert(Object.getPrototypeOf(newObj_1)===UserDefinedFunction.prototype)  //Displays false. The object referenced by UserDefinedFunction.prototype has changed

//The internal reference does not change
alert(newObj_1.constructor) // This shall still Display function UserDefinedFunction

alert(newObj_1.TestProperty) //This shall still Display "test" 

alert(Object.getPrototypeOf(newObj_1).TestProperty) //This shall still Display "test"


//Create another object of type UserDefinedFunction
var newObj_2= new UserDefinedFunction();

alert(Object.getPrototypeOf(newObj_2)===objA) //Displays true.

alert(newObj_2.constructor) //Displays function Array()

alert(newObj_2.property1) //Displays "Property1"

alert(Object.getPrototypeOf(newObj_2).property1) //Displays "Property1"

//Create a new property in objA
objA.property2="property2"

alert(objA.property2) //Displays "Property2"

alert(UserDefinedFunction.prototype.property2) //Displays "Property2"

alert(newObj_2.property2) // Displays Property2

alert(Object.getPrototypeOf(newObj_2).property2) //Displays  "Property2"

Łańcuch prototypów każdego obiektu ostatecznie wraca do obiektu.prototype (który sam w sobie nie posiada żadnego prototypowego obiektu) . Poniższy kod może być użyty do śledzenia łańcucha prototypów obiektu

var o=Starting object;

do {
    alert(o + "\n" + Object.getOwnPropertyNames(o))

}while(o=Object.getPrototypeOf(o))

Prototyp łańcucha dla różnych obiektów pracy Na zewnątrz w następujący sposób.

  • każdy obiekt funkcji (w tym wbudowany obiekt funkcji)-> Funkcja.prototype - > Object.prototype - > null
  • proste obiekty (tworzone przez new Object () lub {} łącznie z wbudowanym w obiekt matematyczny) - > obiekt.prototype - > null
  • obiekt utworzony z new or Object.Utwórz - > jeden lub więcej łańcuchów prototypów - > obiekt.prototype - > null

Do tworzenia obiektu bez prototypu użyj następującego wzoru:

var o=Object.create(null)
alert(Object.getPrototypeOf(o)) //Displays null

One might pomyśl, że ustawienie właściwości prototype konstruktora na null spowoduje utworzenie obiektu z prototypem null. Jednak w takich przypadkach nowo wytworzony prototyp obiektu jest ustawiony na obiekt.prototyp i jego konstruktor jest ustawiony na obiekt funkcyjny. Wynika to z następującego kodu

function UserDefinedFunction(){}
UserDefinedFunction.prototype=null// Can be set to any non object value (number,string,undefined etc.)

var o=new UserDefinedFunction()
alert(Object.getPrototypeOf(o)==Object.prototype)   //Displays true
alert(o.constructor)    //Displays Function Object

W podsumowaniu tego artykułu

  • istnieją dwa typy obiektów typy funkcji i typy funkcji
  • Tylko obiekty typu Function mogą tworzyć nowy obiekt za pomocą operatora new . Tak utworzone obiekty są obiektami typu non Function . Obiekty typu non Function nie mogą dalej tworzyć obiektu za pomocą operatora new .

  • Wszystkie obiekty typu Function domyślnie mają właściwość "prototype". Ta "prototyp" właściwość odwołuje się do obiektu, który ma "konstruktor" właściwość, która przez domyślnie odwołuje się do samego obiektu typu funkcji .

  • Wszystkie obiekty (Function type i Non Function type) mają właściwość "constructor", która domyślnie odwołuje się do obiektu typu Function /Konstruktor , który go stworzył.

  • Każdy obiekt, który zostanie utworzony wewnętrznie odwołuje się do obiektu, do którego odwołuje się "prototyp" własność konstruktora, który go stworzył. Obiekt ten znany jest jako utworzony prototyp obiektu (która różni się od właściwości obiektów typu Function "prototype", do których się odwołuje) . W ten sposób wytworzony obiekt może bezpośrednio uzyskać dostęp do metod i właściwości zdefiniowanych w obiekcie, do których odnosi się właściwość "prototype" konstruktora (w momencie wytworzenia obiektu).

  • Prototyp obiektu (i stąd jego odziedziczone nazwy własności) może być pobrany za pomocą obiektu .metoda getprototype () . W fakt ta metoda może być używany do nawigacji po całym łańcuchu prototypów obiektu.

  • Łańcuch prototypów każdego obiektu ostatecznie wraca do obiektu.prototyp (o ile obiekt nie został wytworzony przy użyciu obiektu.create(null) W takim przypadku obiekt nie ma prototypu).

  • Typeof (new Array ())==='obiekt' jest przez projekt języka, a nie błędem wskazanym przez

  • Ustawianie prototypu właściwość konstruktora do null (lub undefined,number,true,false,string) nie tworzy obiektu z prototypem null. W takim przypadku nowo wytworzony prototyp obiektu jest ustawiony na Object.prototyp i jego konstruktor jest ustawiony na obiekt funkcyjny.

Mam nadzieję, że to pomoże.
 24
Author: Arup Hore,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-11-14 05:09:30

Pojęcie dziedziczenia jest jednym z najbardziej skomplikowanych dla wielu programistów. Spróbujmy zrozumieć źródło problemu, aby lepiej zrozumieć prototypal inheritance. Zacznijmy od funkcji plain.

Tutaj wpisz opis obrazka

Jeśli użyjemy operatora new na Tree function, nazywamy go funkcją constructor.

Tutaj wpisz opis obrazka

Każda JavaScript funkcja ma prototype. Kiedy logujesz Tree.prototype, get...

Tutaj wpisz opis obrazka

Jeśli spojrzysz na powyższe wyjście console.log(), możesz zobaczyć właściwość konstruktora na Tree.prototype oraz właściwość __proto__. To, co się dzieje, to fakt, że jest to tylko zwykły JavaScript function BEZ inheritance jeszcze skonfigurowany, odnosi się do Object prototype, który jest czymś Wbudowanym Do JavaScript...

Https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/prototype

To ma takie rzeczy jak .toString, .toValue, .hasOwnProperty itp...

__proto__ która została wniesiona moja mozilla jest przestarzała i została zastąpiona metodą Object.getPrototypeOf, aby uzyskać object's prototype.

Tutaj wpisz opis obrazka

Object.getPrototypeOf(Tree.prototype); // Object {} 

Dodajmy metodę do naszego Tree prototype.

Tutaj wpisz opis obrazka

Zmodyfikowaliśmy Root i dodaliśmy a function branch to it.

Tutaj wpisz opis obrazka

Oznacza to, że kiedy tworzysz instance z Tree, możesz wywołać metodę branch.

Tutaj wpisz opis obrazka

Możemy również dodać primitives lub objects do naszego Prototype.

Tutaj wpisz opis obrazka

Dodajmy child-tree do naszego Tree.

Tutaj wpisz opis obrazka

Tutaj Child dziedziczy swoje prototype z drzewa, to co robimy tutaj, to użycie metody Object.create() do tworzenia nowy obiekt oparty na tym, co mijasz, oto Tree.prototype. W tym przypadku ustawiamy prototyp dziecka na nowy obiekt, który wygląda identycznie jak prototyp Tree. Następnie ustawiamy Child's constructor to Child, jeśli tego nie zrobimy, wskażemy Tree().

Tutaj wpisz opis obrazka

Child teraz ma swój własny prototype, jego __proto__ wskazuje na Tree i Tree's prototype wskazuje na bazę Object.

Child  
|
 \
  \
   Tree.prototype
   - branch
   |
   |
    \
     \
      Object.prototype
      -toString
      -valueOf
      -etc., etc.

Teraz tworzysz instance Z Child i wywołujesz branch, który jest pierwotnie dostępne w Tree. Nie zdefiniowaliśmy naszego branch na Child prototype. Ale w Root prototype, po którym dziecko dziedziczy.

Tutaj wpisz opis obrazka

W JS wszystko nie jest obiektem, wszystko może działać jak obiekt.

Javascript ma prymitywy jak strings, number, booleans, undefined, null. one nie są object(i.e reference types), ale z pewnością mogą zachowywać się jak object. Spójrzmy na przykład tutaj.

Tutaj wpisz opis obrazka

W pierwszej linijce tej listy, a primitive wartość łańcuchowa jest przypisana do nazwy. Druga linia traktuje nazwę jak object i wywołuje {[62] } używając notacji kropkowej.

To dzieje się za kulisami: // co robi silnik JavaScript

Tutaj wpisz opis obrazka

String object istnieje tylko dla jednej instrukcji, zanim zostanie zniszczona (proces o nazwie autoboxing). Wróćmy jeszcze raz do naszego prototypal inheritance.

  • Javascript obsługuje dziedziczenie poprzez delegation na podstawie prototypes.
  • każdy Function ma prototype własność, która odnosi się do innego obiekt.
  • properties/functions są oglądane z samego object lub przez prototype łańcuch jeśli nie istnieje

A prototype W JS jest obiektem, który yields jest rodzicem innego object. [ie.. delegacja] Delegation oznacza to, że jeśli nie jesteś w stanie czegoś zrobić, powiesz komuś innemu, aby zrobił to za Ciebie.

Tutaj wpisz opis obrazka

Https://jsfiddle.net/say0tzpL/1/

Jeśli spojrzysz dog ma dostęp do metody toString, ale nie jest w niej dostępna, ale dostępna za pośrednictwem łańcucha prototypów, który deleguje do Object.prototype {137]}

Tutaj wpisz opis obrazka

Jeśli spojrzysz na poniższą, staramy się uzyskać dostęp do metody call, która jest dostępna w każdym function.

Tutaj wpisz opis obrazka

Https://jsfiddle.net/rknffckc/

Jeśli spojrzysz wyżej, Profile funkcja ma dostęp do metody call , jednak nie jest on w nim dostępny, ale dostępny za pośrednictwem łańcucha prototypów, który deleguje do Function.prototype {137]}

Tutaj wpisz opis obrazka

Uwaga: prototype jest własnością konstruktora funkcji, podczas gdy {[13] } jest własnością obiektów zbudowanych z konstruktora funkcji. Każda funkcja ma właściwość prototype, której wartość jest pustą object. Kiedy tworzymy instancję funkcji, otrzymujemy wewnętrzną właściwość [[Prototype]] lub __proto__, której referencją jest prototyp funkcji constructor.

Tutaj wpisz opis obrazka

Powyższy diagram wygląda na nieco skomplikowany, ale wydobywa cały obraz tego, jak działa prototype chaining. Przejdźmy przez to powoli:

Istnieją dwie instancje b1 i b2, których konstruktorem jest Bar, a rodzicem jest Foo i ma dwie metody z prototype chain identify i speak poprzez Bar i Foo

Tutaj wpisz opis obrazka

Https://jsfiddle.net/kbp7jr7n/

Jeśli spojrzysz w górę kodu powyżej, mamy Foo konstruktor, który ma metodę identify() i Bar konstruktor, który ma metodę speak. Tworzymy dwie instancje Bar b1 i b2, których typem nadrzędnym jest Foo. Teraz, gdy wywołujemy speak metodę Bar, jesteśmy w stanie zidentyfikować kto wywołuje speak poprzez łańcuch prototype.

Tutaj wpisz opis obrazka

Bar teraz ma wszystkie metody Foo, które są zdefiniowane w jej prototype. Zajrzyjmy dalej w zrozumieniu Object.prototype i Function.prototype i jak są ze sobą powiązane. Jeśli poszukasz konstruktora Foo, Bar i ObjectFunction constructor.

Tutaj wpisz opis obrazka

prototype z Bar jest Foo, prototype z Foo jest Object i jeśli przyjrzymy się dokładnie prototype z Foo jest związane z Object.prototype.

Tutaj wpisz opis obrazka

Zanim to zamkniemy, po prostu owińmy mały fragment kodu tutaj podsumować wszystko powyżej. Używamy tutaj operatora instanceof, aby sprawdzić, czy object ma w swoim łańcuchu prototype właściwość prototype constructor, która poniżej podsumowuje cały duży diagram.

Tutaj wpisz opis obrazka

Mam nadzieję, że ten add to jakieś informacje, wiem, że to może być Duże do uchwycenia... w prostych słowach jego to tylko przedmioty połączone z przedmiotami!!!!

 20
Author: Thalaivar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-03 21:44:50

Jaki jest dokładny cel tego ".prototyp " własność?

Interfejs do standardowych klas staje się rozszerzalny. Na przykład, używasz klasy Array i musisz również dodać niestandardowy serializer dla wszystkich obiektów tablicy. Czy spędzasz czas na kodowaniu podklasy, czy używasz kompozycji lub ... Właściwość prototype 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 vtable-pointer. Gdy brakuje niektórych członków oryginalnej klasy, prototyp jest sprawdzany w czasie wykonywania.

 19
Author: dirkgently,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-21 12:37:38

Może pomóc sklasyfikować łańcuchy prototypów na dwie kategorie.

Rozważmy konstruktor:

 function Person() {}

Wartość Object.getPrototypeOf(Person) jest funkcją. W rzeczywistości jest to Function.prototype. Ponieważ Person została utworzona jako funkcja, posiada ten sam prototypowy obiekt funkcyjny, który posiada wszystkie funkcje. Jest taka sama jak Person.__proto__, ale ta właściwość nie powinna być używana. W każdym razie, z Object.getPrototypeOf(Person) skutecznie wspinasz się po drabinie tak zwanego łańcucha prototypów.

Łańcuch w górę wygląda tak:

PersonFunction.prototypeObject.prototype (punkt końcowy)

Ważne jest to, że ten łańcuch prototypów ma niewiele wspólnego z obiektami, które Person mogą skonstruować . Te konstruowane obiekty mają swój własny łańcuch prototypów, a łańcuch ten może potencjalnie nie mieć wspólnego Bliskiego przodka z wspomnianym powyżej.

Weźmy na przykład Ten obiekt:

var p = new Person();

P nie ma bezpośredniego związku prototypowo-łańcuchowego z osobą . Ich związek jest inny. Obiekt p posiada własny łańcuch prototypów. Używając Object.getPrototypeOf, zobaczysz, że łańcuch jest następujący:

pPerson.prototypeObject.prototype (punkt końcowy)

W tym łańcuchu nie ma obiektu funkcji (choć może być).

Więc Person wydaje się być związane z dwoma rodzajami łańcuchów, które żyją własnym życiem. Aby" przeskoczyć " z jednego łańcucha do drugiego, używasz: {]}

  1. .prototype: skok z łańcucha konstruktora do created-łańcuch obiektu. Ta właściwość jest więc zdefiniowana tylko dla obiektów funkcyjnych (ponieważ new może być używana tylko dla funkcji).

  2. .constructor: przeskocz z łańcucha utworzonego obiektu do łańcucha konstruktora.

Oto wizualna prezentacja dwóch łańcuchów prototypów, reprezentowanych jako kolumny:]}

Tutaj wpisz opis obrazka

Podsumowując:

Właściwość prototype nie podaje informacji o prototypieobiektu łańcuch, ale obiektów stworzonych przez podmiot.

Nie jest zaskoczeniem, że nazwa nieruchomości prototypemoże prowadzić do zamieszania. Może byłoby jaśniej, gdyby ta właściwość została nazwana prototypeOfConstructedInstances lub coś w tym stylu. Możesz przeskakiwać między dwoma łańcuchami prototypów:]}
Person.prototype.constructor === Person

Ta symetria może zostać złamana przez jawne przypisanie innego obiektu do właściwości prototype (więcej o tym później).

Utwórz Function, Get Two Objects

Person.prototype jest obiektem, który został utworzony w tym samym czasie, w którym została utworzona funkcja Person. Ma Person jako konstruktor, mimo że ten konstruktor jeszcze nie wykonał. Tak więc dwa obiekty są tworzone w tym samym czasie:

  1. funkcja Person sama w sobie
  2. Obiekt, który będzie działał jako prototyp, gdy funkcja zostanie wywołana jako konstruktor]}

Oba są obiektami, ale mają różne role: obiekt funkcji konstruuje , podczas gdy drugi obiekt reprezentuje prototyp dowolnego obiektu, który zbuduje funkcja. Prototypowy obiekt stanie się rodzicem konstruowanego obiektu w jego łańcuchu prototypów.

Ponieważ funkcja jest również obiektem, ma również swój rodzic we własnym łańcuchu prototypów, ale przypomnijmy, że te dwa łańcuchy dotyczą różnych rzeczy.

Oto kilka równań, które mogłyby pomóc zrozumieć problem - wszystkie te druki true:

function Person() {};

// This is prototype chain info for the constructor (the function object):
console.log(Object.getPrototypeOf(Person) === Function.prototype);
// Step further up in the same hierarchy:
console.log(Object.getPrototypeOf(Function.prototype) === Object.prototype);
console.log(Object.getPrototypeOf(Object.prototype) === null);
console.log(Person.__proto__ === Function.prototype);
// Here we swap lanes, and look at the constructor of the constructor
console.log(Person.constructor === Function);
console.log(Person instanceof Function);

// Person.prototype was created by Person (at the time of its creation)
// Here we swap lanes back and forth:
console.log(Person.prototype.constructor === Person);
// Although it is not an instance of it:
console.log(!(Person.prototype instanceof Person));
// Instances are objects created by the constructor:
var p = new Person();
// Similarly to what was shown for the constructor, here we have
// the same for the object created by the constructor:
console.log(Object.getPrototypeOf(p) === Person.prototype);
console.log(p.__proto__ === Person.prototype);
// Here we swap lanes, and look at the constructor
console.log(p.constructor === Person);
console.log(p instanceof Person);

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żywany jako prototyp dla kolejnych wystąpień utworzonych przez ten konstruktor.

Na przykład:

function Thief() { }
var p = new Person();
Thief.prototype = p; // this determines the prototype for any new Thief objects:
var t = new Thief();

Teraz łańcuch prototypu t jest o krok dłuższy od p :

    tpPerson.prototypeObject.prototype (punkt końcowy)

W przeciwieństwie do innych łańcuchów prototypów, nie są one dłuższe: Thief i Person są rodzeństwem dzielącym tego samego rodzica w łańcuchu prototypów:

    Person}
    Thief } → Function.prototypeObject.prototype (punkt końcowy)

Wcześniej prezentowana grafika może być następnie rozszerzona o to (oryginał {[41] } jest pominięty):

Tutaj wpisz opis obrazka

Niebieskie linie reprezentują łańcuchy prototypów, Pozostałe kolorowe linie reprezentują inne relacje:

  • pomiędzy obiektem a jego konstruktorem
  • pomiędzy konstruktorem a prototypowym obiektem, który będzie używany do konstruowania obiektów
 17
Author: trincot,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-22 20:59:37

The Definitive Guide to Object-Oriented JavaScript - bardzo zwięzłe i jasne ~30min wideo Wyjaśnienie zadanego pytania (temat dziedziczenia prototypów zaczyna się od 5:45, chociaż wolę posłuchać całego filmiku). Autor tego filmu stworzył również Stronę JavaScript object visualizer http://www.objectplayground.com/.Tutaj wpisz opis obrazka Tutaj wpisz opis obrazka

 16
Author: Bad,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-18 17:30:56

Uznałem za pomocne Wyjaśnienie "łańcucha prototypów" jako konwencji rekurencyjnej, gdyobj_n.prop_X jest odwołany:

Jeśli obj_n.prop_X nie istnieje, sprawdź obj_n+1.prop_X Gdzie obj_n+1 = obj_n.[[prototype]]

Jeśli prop_X zostanie ostatecznie znaleziony w K-tym obiekcie prototypowym, to

obj_1.prop_X = obj_1.[[prototype]].[[prototype]]..(k-times)..[[prototype]].prop_X

Wykres relacji obiektów Javascript według ich właściwości znajdziesz tutaj:

Wykres obiektów js

Http://jsobjects.org

 13
Author: B M,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-12-09 11:45:44

Gdy Konstruktor tworzy obiekt, obiekt ten domyślnie odwołuje się do właściwości "prototype" konstruktora w celu rozwiązania odniesień do właściwości. Właściwość "prototype" konstruktora może być odwołana przez konstruktor wyrażenia programu.prototype i właściwości dodane do prototypu obiektu są współdzielone, poprzez dziedziczenie, przez wszystkie obiekty współdzielące prototyp.

 12
Author: Tom,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-05 18:42:10

Pozwól, że opowiem ci o moim zrozumieniu prototypów. Nie będę tu porównywał dziedziczenia z innymi językami. Chciałbym, aby ludzie przestali porównywać Języki i po prostu rozumieli język jako sam w sobie. Zrozumienie prototypów i dziedziczenia prototypów jest tak proste, jak pokażę poniżej.

Prototyp jest jak model, na podstawie którego tworzysz produkt. Kluczowym punktem do zrozumienia jest to, że gdy tworzysz obiekt używając innego obiektu jako prototypu, link między prototypem a produktem jest zawsze trwały. Na przykład:

var model = {x:2};
var product = Object.create(model);
model.y = 5;
product.y
=>5

Każdy obiekt zawiera wewnętrzną właściwość o nazwie [[prototype]], do której można uzyskać dostęp za pomocą funkcji Object.getPrototypeOf(). Object.create(model) tworzy nowy obiekt i ustawia jego właściwość [[prototype]] na obiekt model . Dlatego gdy wykonasz Object.getPrototypeOf(product), otrzymasz model obiektu .

Właściwości produktu są obsługiwane w następujący sposób:

  • gdy nieruchomość jest dostępna do po prostu odczytaj jego wartość, poszukaj jej w łańcuchu lunet. Wyszukiwanie zmiennej rozpoczyna się od produktu w górę do jej prototypu. Jeśli taka zmienna zostanie znaleziona w wyszukiwaniu, wyszukiwanie zostanie zatrzymane w tym miejscu, a wartość zostanie zwrócona. Jeśli taka zmienna nie może zostać znaleziona w łańcuchu zakresu, zwracana jest undefined.
  • gdy właściwość jest zapisywana (zmieniana), wtedy właściwość jest zawsze zapisywana na obiekcie product. Jeżeli Produkt nie ma takiego właściwość już jest niejawnie tworzona i zapisywana.

Takie łączenie obiektów za pomocą właściwości prototype nazywa się dziedziczeniem prototypowym. To takie proste, prawda?

 9
Author: Aravind,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-11-09 15:59:28

Rozważmy następujący obiekt keyValueStore:

var keyValueStore = (function() {
    var count = 0;
    var kvs = function() {
        count++;
        this.data = {};
        this.get = function(key) { return this.data[key]; };
        this.set = function(key, value) { this.data[key] = value; };
        this.delete = function(key) { delete this.data[key]; };
        this.getLength = function() {
            var l = 0;
            for (p in this.data) l++;
            return l;
        }
    };

    return  { // Singleton public properties
        'create' : function() { return new kvs(); },
        'count' : function() { return count; }
    };
})();

Mogę utworzyć nową instancję tego obiektu, wykonując to :

kvs = keyValueStore.create();

Każda instancja tego obiektu będzie miała następujące właściwości publiczne:

  • data
  • get
  • set
  • delete
  • getLength

Załóżmy, że utworzymy 100 instancji tego keyValueStore obiektu. Chociaż get, set, delete, getLength zrobi dokładnie to samo dla każdego z tych 100 przypadków, każda instancja posiada własną kopię tej funkcji.

A teraz wyobraź sobie, że możesz mieć tylko jedną get, set, delete i getLength skopiować, a każda instancja odwoływałaby się do tej samej funkcji. Byłoby to lepsze dla wydajności i wymaga mniej pamięci.

Oto, gdzie pojawiają się prototypy. Prototyp jest "schematem" właściwości, które są dziedziczone, ale nie kopiowane przez instancje. Oznacza to, że istnieje on tylko raz w pamięci dla wszystkich instancji obiektu i jest współdzielony przez wszystkie z tych przypadków.

Zastanów się jeszcze raz nad obiektem. Mógłbym to przepisać w ten sposób:
var keyValueStore = (function() {
    var count = 0;
    var kvs = function() {
        count++;
        this.data = {};
    };

    kvs.prototype = {
        'get' : function(key) { return this.data[key]; },
        'set' : function(key, value) { this.data[key] = value; },
        'delete' : function(key) { delete this.data[key]; },
        'getLength' : function() {
            var l = 0;
            for (p in this.data) l++;
            return l;
        }
    };

    return  {
        'create' : function() { return new kvs(); },
        'count' : function() { return count; }
    };
})();

Robi to dokładnie tak samo jak poprzednia wersja obiektu keyValueStore, z tym że wszystkie jego metody są teraz umieszczone w prototypie. Oznacza to, że wszystkie instancje 100 mają teraz te cztery metody, a nie każda z nich ma własną kopię.

 8
Author: John Slegers,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-11 19:24:36

Istnieją dwa odrębne, ale powiązane podmioty, które wymagają wyjaśnienia:

  • właściwość .prototype funkcji.
  • The [[Prototype]][1] własność wszystkich obiektów[2].
To są dwie różne rzeczy.

Właściwość [[Prototype]]:

Jest to właściwość, która istnieje na wszystkich[2] obiektów.

To, co tu jest przechowywane, to inny obiekt, który jako obiekt sam w sobie ma [[Prototype]] z swój własny, który wskazuje na inny obiekt. Ten drugi obiekt ma [[Prototype]] swój własny. Ta historia trwa do momentu dotarcia do prototypowego obiektu, który zapewnia metody dostępne dla wszystkich obiektów (np. .toString).

Właściwość [[Prototype]] jest częścią tego, co tworzy łańcuch [[Prototype]]. Ten łańcuch obiektów [[Prototype]] jest tym, co jest badane, gdy na przykład operacje [[Get]] lub [[Set]] są wykonywane na obiekcie:

var obj = {}
obj.a         // [[Get]] consults prototype chain
obj.b = 20    // [[Set]] consults prototype chain

Właściwość .prototype:

to jest nieruchomość występuje tylko w funkcjach. używając bardzo prostej funkcji:

function Bar(){};

Właściwość .prototype zawiera obiekt , który zostanie przypisany do b.[[Prototype]], gdy wykonasz var b = new Bar. Można to łatwo zbadać:

// Both assign Bar.prototype to b1/b2[[Prototype]]
var b = new Bar;
// Object.getPrototypeOf grabs the objects [[Prototype]]
console.log(Object.getPrototypeOf(b) === Bar.prototype) // true

Jednym z najważniejszych .prototype s jest z Object funkcji . Ten prototyp zawiera prototypowy obiekt, który zawierają wszystkie [[Prototype]] łańcuchy. Na nim zdefiniowane są wszystkie dostępne metody dla nowych obiektów:

// Get properties that are defined on this object
console.log(Object.getOwnPropertyDescriptors(Object.prototype))

Teraz, ponieważ .prototype jest obiekt, posiada właściwość [[Prototype]]. Kiedy nie wykonujesz żadnych przydziałów do Function.prototype, .prototype ' s [[Prototype]] wskazuje na prototypowy obiekt (Object.prototype). Jest to wykonywane automatycznie za każdym razem, gdy tworzysz nową funkcję.

W ten sposób, za każdym razem, gdy zrobisz new Bar; łańcuch prototypów jest ustawiony dla Ciebie, otrzymasz wszystko zdefiniowane na Bar.prototype i wszystko zdefiniowane na Object.prototype:

var b = new Bar;
// Get all Bar.prototype properties
console.log(b.__proto__ === Bar.prototype)
// Get all Object.prototype properties
console.log(b.__proto__.__proto__ === Object.prototype)

Kiedy wykonujesz zadania do Function.prototype wszystko, co robisz, to rozszerzenie łańcucha prototypów o inny obiekt. To jak wstawka na pojedynczo połączonej liście.

To zasadniczo zmienia łańcuch [[Prototype]] pozwalając właściwościom zdefiniowanym na obiekcie przypisanym do Function.prototype być widzianym przez dowolny obiekt utworzony przez funkcję.


[1: to nie myli nikogo; udostępniane za pośrednictwem właściwości __proto__ w wielu implementacjach.
[2]: wszystkie z wyjątkiem null.

 8
Author: Jim Fasarakis Hilliard,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-03 17:46:58

Kolejna próba wyjaśnienia dziedziczenia opartego na prototypach JavaScript z lepszymi obrazkami

Proste obiekty inheritanse

 7
Author: rus1,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-10-24 21:27:45

Zawsze lubię analogie, jeśli chodzi o rozumienie tego typu rzeczy. "Dziedziczenie prototypowe" jest moim zdaniem dość mylące w porównaniu z dziedziczeniem basów klasycznych, mimo że prototypy są znacznie prostszym paradygmatem. W rzeczywistości w przypadku prototypów naprawdę nie ma dziedziczenia, więc nazwa sama w sobie wprowadza w błąd, jest bardziej rodzajem "delegacji".

Wyobraź to sobie ....

Jesteś w liceum, a jesteś w klasie i masz quiz, który jest do dziś, ale nie masz długopis do wypełnienia 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 mówić "nie mam długopisu", jest miłym przyjacielem, sprawdza u swojego drugiego przyjaciela Derpa, czy ma długopis. Derp rzeczywiście ma zapasowy długopis i przekazuje go Finniusowi, który przekazuje go tobie, aby ukończyć quiz. Derp powierzył wstrzykiwacz Finniusowi, który przekazał wstrzykiwacz tobie do użycia.

Co to jest ważne jest to, że Derp nie daje Ci długopisu, ponieważ nie masz z nim bezpośredniego związku .

Jest to uproszczony przykład działania prototypów, gdzie drzewo danych jest wyszukiwane dla rzeczy, której szukasz.

 7
Author: Louis Moore,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-09 04:49:52

Podsumowanie:

  • funkcje są obiektami w javascript i mogą mieć właściwości
  • (Konstruktor) funkcje zawsze mają właściwość prototypu
  • gdy funkcja jest używana jako konstruktor ze słowem kluczowym new, obiekt otrzymuje właściwość __proto__
  • ta właściwość __proto__ odnosi się do właściwości prototype funkcji konstruktora.

Przykład:

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

let me = new Person('willem');

console.log(Person.prototype) // Person has a prototype property

console.log(Person.prototype === me.__proto__) // the __proto__ property of the instance refers to prototype property of the function.

Dlaczego jest to przydatne:

Javascript ma mechanizm podczas wyszukiwania właściwości na obiektach, które nazywa się 'dziedziczenie prototypowe' , Oto co zasadniczo robi:

  • najpierw jest sprawdzane, czy właściwość znajduje się na samym obiekcie. Jeśli tak, ta właściwość jest zwracana.
  • Jeśli właściwość nie znajduje się na samym obiekcie, "wspina się po protochainie". Zasadniczo wygląda na obiekt, do którego odnosi się właściwość proto . Tam sprawdza, czy właściwość jest dostępna na danym obiekcie to by proto
  • Jeśli właściwość nie znajduje się na proto obiekt będzie wspinać się w górę proto łańcuch aż do obiektu obiekt.
  • Jeśli nie znajdzie właściwości nigdzie w obiekcie i jego łańcuchu prototypów, zwróci undefined.

Na przykład:

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

let mySelf = new Person('Willem');

console.log(mySelf.__proto__ === Person.prototype);

console.log(mySelf.__proto__.__proto__ === Object.prototype);
 2
Author: Willem van der Veen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-18 10:24:20

Its just that you already have a object with Object.nowy, ale nadal nie masz obiektu przy użyciu składni konstruktora.

 1
Author: shiva kumar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-01 09:33:06

Kolejny schemat pokazujący _ _ proto__, Prototype and constructor relations: Tutaj wpisz opis obrazka

 1
Author: IvanM,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-02 06:21:42