Jest to bardzo prosty prototypowy model obiektowy, który podczas objaśnienia byłby traktowany jako próbka, bez komentarza:
function Person(name){
this.name = name;
}
Person.prototype.getName = function(){
console.log(this.name);
}
var person = new Person("George");
Jest kilka kluczowych punktów, które musimy wziąć pod uwagę przed omówieniem koncepcji prototypu.
1- Jak faktycznie działają funkcje JavaScript:
Aby zrobić pierwszy krok, musimy dowiedzieć się, jak faktycznie działają funkcje JavaScript, jako klasa taka jak funkcja wykorzystująca this
słowo kluczowe lub po prostu jako zwykła funkcja z argumentami, co robi i co zwraca.
Powiedzmy, że chcemy stworzyć Person
model obiektowy. ale w tym kroku będę próbował zrobić dokładnie to samo bez użycia słowa kluczowego prototype
inew
.
Więc na tym etapie functions
, objects
a this
słowa kluczowego, to wszystko, co mamy.
Pierwszym pytaniem byłoby, w jaki sposób this
słowo kluczowe może być przydatne bez uż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, w jaki sposób moglibyśmy korzystać z tych funkcji. JavaScript ma więc 3 różne sposoby:
za. pierwszym sposobem jest wywołanie funkcji jako zwykłej funkcji:
Person("George");
getName();//would print the "George" in the console
w tym przypadku byłby to bieżący obiekt kontekstu, którym zwykle jest window
obiekt globalny w przeglądarce lub GLOBAL
w Node.js
. Oznacza to, że mielibyśmy, window.name w przeglądarce lub GLOBAL.name w Node.js, z „George” jako jego wartością.
b. Możemy dołączyć je do obiektu jako jego właściwości
- Najłatwiej to zrobić, modyfikując pusteperson
obiekt, na przykład:
person.Person = Person;
person.getName = getName;
w ten sposób możemy je nazwać:
person.Person("George");
person.getName();// -->"George"
a teraz person
obiekt jest jak:
Object {Person: function, getName: function, name: "George"}
- Innym sposobem dołączenia właściwości do obiektu jest użycie prototype
tego obiektu, który można znaleźć w dowolnym obiekcie JavaScript o nazwie __proto__
, i próbowałem wyjaśnić to trochę w części podsumowującej. Możemy więc uzyskać podobny wynik, wykonując:
person.__proto__.Person = Person;
person.__proto__.getName = getName;
Ale w ten sposób faktycznie modyfikujemy Object.prototype
, ponieważ za każdym razem, gdy tworzymy obiekt JavaScript za pomocą literals ( { ... }
), jest on tworzony na podstawie Object.prototype
, co oznacza, że zostaje on dołączony do nowo utworzonego obiektu jako atrybut o nazwie__proto__
, więc jeśli go zmienimy , podobnie jak w przypadku naszego poprzedniego fragmentu kodu, wszystkie obiekty JavaScript zostałyby zmienione, co nie jest dobrą praktyką. Więc jaka może być teraz lepsza praktyka:
person.__proto__ = {
Person: Person,
getName: getName
};
a teraz inne przedmioty są spokojne, ale nadal nie wydaje się to dobrą praktyką. Mamy więc jeszcze jedno rozwiązanie, ale aby skorzystać z tego rozwiązania, powinniśmy wrócić do tego wiersza kodu, w którym person
utworzono obiekt (var person = {};
), a następnie zmienić go w następujący sposób:
var propertiesObject = {
Person: Person,
getName: getName
};
var person = Object.create(propertiesObject);
tworzy nowy JavaScript Object
i dołącza go propertiesObject
do pliku__proto__
atrybutu. Aby upewnić się, że możesz:
console.log(person.__proto__===propertiesObject); //true
Problem w tym, że masz dostęp do wszystkich właściwości zdefiniowanych __proto__
na pierwszym poziomieperson
obiektu (więcej szczegółów znajdziesz w części podsumowującej).
jak widzisz, używając dowolnego z tych dwóch sposobów this
wskazywałoby dokładnie na person
obiekt.
do. JavaScript ma inny sposób na zapewnienie funkcji this
, która polega na wywołaniu lub zastosowaniu do wywołania funkcji.
Metoda apply () wywołuje funkcję o podanej wartości i argumentach podanych jako tablica (lub obiekt podobny do tablicy).
i
Metoda call () wywołuje funkcję o podanej wartości i argumentach podanych indywidualnie.
w ten sposób, który jest moim ulubionym, możemy łatwo wywoływać nasze funkcje, takie jak:
Person.call(person, "George");
lub
//apply is more useful when params count is not fixed
Person.apply(person, ["George"]);
getName.call(person);
getName.apply(person);
te 3 metody są ważnymi początkowymi krokami do zrozumienia funkcjonalności .prototypu.
2- Jak działa new
słowo kluczowe?
to jest drugi krok do zrozumienia .prototype
funkcjonalności. oto, czego używam do symulacji procesu:
function Person(name){ this.name = name; }
my_person_prototype = { getName: function(){ console.log(this.name); } };
w tej części postaram się wykonać wszystkie kroki, które wykonuje JavaScript, bez użycia new
słowa kluczowego i prototype
, gdy używasz new
słowa kluczowego. więc kiedy to robimy new Person("George")
, Person
funkcja służy jako konstruktor. Oto, co robi JavaScript, jeden po drugim:
za. po pierwsze tworzy pusty obiekt, w zasadzie pusty skrót, taki jak:
var newObject = {};
b. następnym krokiem JavaScript jest dołączenie wszystkich prototypowych obiektów do nowo utworzonego obiektu
mamy my_person_prototype
tutaj podobny do obiektu prototypowego.
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 związany jest z koncepcją łańcucha prototypów.
za. & b. Zamiast tych dwóch kroków możesz uzyskać dokładnie taki sam wynik, wykonując:
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 wywołać getName
funkcję w naszym my_person_prototype
:
newObject.getName();
do. następnie przekazuje ten obiekt do konstruktora,
możemy to zrobić za pomocą naszej próbki, takiej jak:
Person.call(newObject, "George");
lub
Person.apply(newObject, ["George"]);
wtedy konstruktor może zrobić, co chce, ponieważ to wewnątrz tego konstruktora jest obiekt, który został właśnie utworzony.
teraz wynik końcowy przed symulacją innych kroków: Object {name: "George"}
Podsumowanie:
Zasadniczo, gdy używasz nowego słowa kluczowego w funkcji, wywołujesz tę funkcję, a ta funkcja służy jako konstruktor, więc mówiąc:
new FunctionName()
JavaScript wewnętrznie tworzy obiekt, pusty skrót, a następnie przekazuje ten obiekt do konstruktora, a następnie konstruktor może zrobić co chce, ponieważ to wewnątrz tego konstruktora jest właśnie utworzonym obiektem, a następnie daje ten obiekt oczywiście jeśli nie użyłeś instrukcji return w swojej funkcji lub jeśli umieściłeś return undefined;
na końcu treści funkcji.
Kiedy JavaScript zaczyna szukać właściwości na obiekcie, pierwszą rzeczą, którą robi, jest wyszukiwanie na tym obiekcie. A potem jest tajna właściwość, [[prototype]]
którą zwykle mamy, __proto__
a ta właściwość właśnie patrzy na JavaScript. A kiedy przegląda __proto__
, o ile jest to kolejny obiekt JavaScript, ma swój własny __proto__
atrybut, idzie w górę i w górę, aż dojdzie do punktu, w którym następny __proto__
jest pusty. Punkt jest jedynym obiektem w JavaScript, którego __proto__
atrybut ma wartość null, to 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ść prototypową funkcji i wywołujesz nową funkcję, po zakończeniu JavaScript w poszukiwaniu tego nowo utworzonego obiektu pod kątem właściwości, przejdzie on do funkcji .prototype
i możliwe jest, że ten obiekt ma swoją własny wewnętrzny prototyp. i tak dalej.