Pierwszą różnicę można streścić w następujący sposób: this
odnosi się do wystąpienia klasy. prototype
odnosi się do definicji .
Powiedzmy, że mamy następującą klasę:
var Flight = function ( number ) { this.number = number; };
Tak więc tutaj przywiązujemy się this.number
do każdej instancji klasy i ma to sens, ponieważ każdy Flight
powinien mieć swój własny numer lotu.
var flightOne = new Flight( "ABC" );
var flightTwo = new Flight( "XYZ" );
W przeciwieństwie, prototype
definiuje pojedynczą właściwość, do której mogą mieć dostęp wszystkie instancje.
Teraz, jeśli chcemy uzyskać numer lotu, możemy po prostu napisać następujący fragment kodu, a wszystkie nasze instancje otrzymają odniesienie do tego nowo prototypowanego obiektu.
Flight.prototype.getNumber = function () { return this.number; };
Druga różnica dotyczy sposobu, w jaki JavaScript wyszukuje właściwość obiektu. Kiedy szukasz Object.whatever
, JavaScript dociera aż do głównego obiektu (obiektu, który odziedziczył wszystko inne), a gdy tylko znajdzie dopasowanie, zwróci go lub wywoła.
Ale dzieje się tak tylko w przypadku prototypowanych właściwości. Więc jeśli masz gdzieś na wyższych poziomach this.whatever
, JavaScript nie uzna tego za dopasowanie i kontynuuje wyszukiwanie.
Zobaczmy, jak to się dzieje w rzeczywistości.
Pierwsza uwaga, że [prawie] wszystko to Obiekty w JavaScript. Spróbuj tego:
typeof null
Zobaczmy teraz, co jest w środku Object
(zwróć uwagę na wielkie litery O
i .
na końcu). Po wejściu do Narzędzi programistycznych Google Chrome .
zobaczysz listę dostępnych właściwości w tym konkretnym obiekcie.
Object.
Teraz zrób to samo dla Function
:
Function.
Możesz zauważyć name
metodę. Po prostu uruchom go i zobaczmy, co się stanie:
Object.name
Function.name
Teraz stwórzmy funkcję:
var myFunc = function () {};
Zobaczmy też, czy mamy name
tutaj metodę:
myFunc.name
Powinieneś dostać pusty ciąg, ale to dobrze. Nie powinieneś otrzymywać błędu ani wyjątku.
Teraz dodajmy coś do tego boskiego Object
i zobaczmy, czy dostaniemy to również w innych miejscach?
Object.prototype.test = "Okay!";
I proszę bardzo:
Object.prototype.test
Function.prototype.test
myFunc.prototype.test
We wszystkich przypadkach powinieneś zobaczyć "Okay!"
.
Jeśli chodzi o zalety i wady każdej metody, można rozważyć prototypowanie jako „bardziej wydajny” sposób wykonywania zadań, ponieważ zachowuje on referencje w każdym przypadku, a raczej kopiuje całą właściwość w każdym obiekcie. Z drugiej strony jest to przykład Tightly Coupling, który jest dużym nie-nie, dopóki nie będziesz w stanie naprawdę uzasadnić przyczyny.this
jest znacznie bardziej skomplikowany, ponieważ dotyczy kontekstu. W Internecie można znaleźć wiele dobrych zasobów za darmo.
To powiedziawszy, oba sposoby są tylko narzędziami językowymi i to naprawdę zależy od ciebie i problemu, który próbujesz rozwiązać, aby wybrać to, co pasuje lepiej.
Jeśli potrzebujesz mieć właściwość odpowiednią dla każdej instancji klasy, użyj this
. Jeśli potrzebujesz właściwości, aby działała tak samo w każdej instancji, użyj prototype
.
Aktualizacja
Jeśli chodzi o przykładowe fragmenty, pierwszy jest przykładem Singletona , więc sensowne jest użycie go this
w ciele obiektu. Możesz także ulepszyć swój przykład, czyniąc go tak modułowym (i nie zawsze musisz go również używać this
).
/* Assuming it will run in a web browser */
(function (window) {
window.myApp = {
...
}
})( window );
/* And in other pages ... */
(function (myApp) {
myApp.Module = {
...
}
})( myApp );
/* And if you prefer Encapsulation */
(function (myApp) {
myApp.Module = {
"foo": "Foo",
"bar": function ( string ) {
return string;
},
return {
"foor": foo,
"bar": bar
}
}
})( myApp );
Twój drugi fragment nie ma większego sensu, ponieważ najpierw go używasz, this
a później próbujesz go zhakować prototype
, co nie działa, ponieważ this
ma wyższy priorytet prototype
. Nie jestem pewien, jakie były twoje oczekiwania wobec tego fragmentu kodu i jak działał, ale bardzo polecam, aby go przeredagować.
Aktualizacja
Aby rozwinąć this
kwestię pierwszeństwa prototype
, mogę pokazać przykład i wyjaśnić, jak można to wyjaśnić, ale nie mam żadnych zewnętrznych zasobów, aby je wykonać.
Przykład jest bardzo prosty:
var myClass = function () { this.foo = "Foo"; };
myClass.prototype.foo = "nice try!";
myClass.prototype.bar = "Bar";
var obj = new myClass;
obj.foo; // Still contains "Foo" ...
obj.bar; // Contains "Bar" as expected
Wyjaśnienie jest, jak wiemy, this
istotne w kontekście. Więc nie powstanie, dopóki kontekst nie będzie gotowy. Kiedy kontekst jest gotowy? Podczas tworzenia nowej instancji! Resztę powinieneś odgadnąć! Oznacza to, że chociaż istnieje prototype
definicja, ale this
bardziej sensowne jest nadanie pierwszeństwa, ponieważ chodzi o tworzenie nowej instancji w tym momencie.