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.
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.
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);
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.
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.
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ę.
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
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.
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
Można go pobrać za pomocą ES5[[Prototype]]
w 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 wobj.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 przezobj.p = ...
lubObject.defineProperty(obj, ...)
- właściwości
obj.__proto__
- właściwości
obj.__proto__.__proto__
i tak dalej - jeśli jakieś
__proto__
jestnull
, 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
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
.
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.
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
- obiekty typu Function
- 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.
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
.
Jeśli użyjemy operatora new
na Tree function
, nazywamy go funkcją constructor
.
Każda JavaScript
funkcja ma prototype
. Kiedy logujesz Tree.prototype
, get...
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
.
Object.getPrototypeOf(Tree.prototype); // Object {}
Dodajmy metodę do naszego Tree
prototype
.
Zmodyfikowaliśmy Root
i dodaliśmy a function
branch to it.
Oznacza to, że kiedy tworzysz instance
z Tree
, możesz wywołać metodę branch
.
Możemy również dodać primitives
lub objects
do naszego Prototype
.
Dodajmy child-tree
do naszego Tree
.
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()
.
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.
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.
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
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 poprzezdelegation
na podstawieprototypes
. - każdy
Function
maprototype
własność, która odnosi się do innego obiekt. -
properties/functions
są oglądane z samegoobject
lub przezprototype
ł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.
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]}
Jeśli spojrzysz na poniższą, staramy się uzyskać dostęp do metody call
, która jest dostępna w każdym function
.
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]}
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
.
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
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
.
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 Object
są Function constructor
.
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
.
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.
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!!!!
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.
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:
Person
→ Function.prototype
→ Object.prototype
(punkt końcowy)
Ważne jest to, że ten łańcuch prototypów ma niewiele wspólnego z obiektami, które Person
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:
p
→ Person.prototype
→ Object.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: {]}
.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)..constructor
: przeskocz z łańcucha utworzonego obiektu do łańcucha konstruktora.
Podsumowując:
Nie jest zaskoczeniem, że nazwa nieruchomościWłaściwość
prototype
nie podaje informacji o prototypieobiektu łańcuch, ale obiektów stworzonych przez podmiot.
prototype
moż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:
- funkcja
Person
sama w sobie
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 :
t
→ p
→ Person.prototype
→ Object.prototype
(punkt końcowy)
Thief
i Person
są rodzeństwem dzielącym tego samego rodzica w łańcuchu prototypów:
Person
}
Thief
} → Function.prototype
→ Object.prototype
(punkt końcowy)
Wcześniej prezentowana grafika może być następnie rozszerzona o to (oryginał {[41] } jest pominięty):
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
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/.
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:
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.
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?
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ę.
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].
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
.
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
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.
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ściprototype
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);
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.
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
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