Prototypy to optymalizacja .
Świetnym przykładem ich dobrego wykorzystania jest biblioteka jQuery. Za każdym razem, gdy uzyskujesz obiekt jQuery przy użyciu $('.someClass')
, obiekt ten ma dziesiątki „metod”. Biblioteka mogłaby to osiągnąć, zwracając obiekt:
return {
show: function() { ... },
hide: function() { ... },
css: function() { ... },
animate: function() { ... },
};
Ale to oznaczałoby, że każdy obiekt jQuery w pamięci miałby dziesiątki nazwanych slotów zawierających w kółko te same metody.
Zamiast tego metody te są zdefiniowane w prototypie, a wszystkie obiekty jQuery „dziedziczą” ten prototyp, aby uzyskać wszystkie te metody przy bardzo niewielkim koszcie wykonania.
Niezwykle ważną częścią tego, jak jQuery robi to dobrze, jest to, że jest to ukryte przed programistą. Traktuje się go wyłącznie jako optymalizację, a nie jako coś, o co musisz się martwić podczas korzystania z biblioteki.
Problem z JavaScriptem polega na tym, że nagie funkcje konstruktora wymagają, aby wywołujący pamiętał, aby poprzedzić je przedrostkiem new
lub w przeciwnym razie zazwyczaj nie działają. Nie ma ku temu dobrego powodu. jQuery robi to dobrze, ukrywając ten nonsens za zwykłą funkcją $
, więc nie musisz przejmować się implementacją obiektów.
Aby można było wygodnie utworzyć obiekt z określonym prototypem, ECMAScript 5 zawiera standardową funkcję Object.create
. Znacznie uproszczona wersja wyglądałaby tak:
Object.create = function(prototype) {
var Type = function () {};
Type.prototype = prototype;
return new Type();
};
Dba o ból związany z pisaniem funkcji konstruktora, a następnie wywoływaniem jej za pomocą new
.
Kiedy unikałbyś prototypów?
Użyteczne porównanie jest z popularnymi językami OO, takimi jak Java i C #. Obsługują one dwa rodzaje dziedziczenia:
- Interfejs dziedziczenia, gdzie takie, że klasa udostępnia swój niepowtarzalny realizacji dla każdego członka interfejsu.
implement
interface
- dziedziczenie implementacji , gdzie
extend
jest class
dostarczana domyślna implementacja niektórych metod.
W JavaScript dziedziczenie prototypowe jest rodzajem dziedziczenia implementacyjnego . Tak więc w sytuacjach, w których (w C # lub Javie) wyprowadziłbyś z klasy bazowej, aby uzyskać domyślne zachowanie, do którego następnie wprowadzasz niewielkie modyfikacje za pomocą zastąpień, wtedy w JavaScript ma sens dziedziczenie prototypowe.
Jeśli jednak jesteś w sytuacji, w której używałbyś interfejsów w C # lub Javie, nie potrzebujesz żadnej konkretnej funkcji językowej w JavaScript. Nie ma potrzeby jawnego deklarowania czegoś, co reprezentuje interfejs i nie ma potrzeby oznaczania obiektów jako „implementujących” ten interfejs:
var duck = {
quack: function() { ... }
};
duck.quack();
Innymi słowy, jeśli każdy „typ” obiektu ma swoje własne definicje „metod”, to dziedziczenie z prototypu nie ma wartości. Następnie zależy to od liczby przydzielonych instancji każdego typu. Jednak w wielu projektach modułowych występuje tylko jeden egzemplarz danego typu.
W rzeczywistości wiele osób sugerowało, że dziedziczenie implementacji jest złe . Oznacza to, że jeśli istnieją pewne typowe operacje dla typu, być może jest to bardziej zrozumiałe, jeśli nie są one umieszczane w klasie podstawowej / super, ale zamiast tego są ujawniane jako zwykłe funkcje w jakimś module, do którego przekazujesz obiekt (y) chcesz na nich operować.
quack
funkcja była w prototypie, z którym jest połączonych wiele instancji kaczki. 2. Składnia literału obiektu{ ... }
tworzy instancję (nie ma potrzeby używanianew
z nią). 3. Wywołanie dowolnej funkcji JS powoduje utworzenie przynajmniej jednego obiektu w pamięci - nazywa sięarguments
obiektem i przechowuje argumenty przekazane w wywołaniu: developer.mozilla.org/en/JavaScript/Reference/ ...Powinieneś używać prototypów, jeśli chcesz zadeklarować „niestatyczną” metodę obiektu.
var myObject = function () { }; myObject.prototype.getA = function (){ alert("A"); }; myObject.getB = function (){ alert("B"); }; myObject.getB(); // This works fine myObject.getA(); // Error! var myPrototypeCopy = new myObject(); myPrototypeCopy.getA(); // This works, too.
źródło
this
przykładu,this.getA = function(){alert("A")}
prawda?Jednym z powodów używania wbudowanego
prototype
obiektu jest wielokrotne powielanie obiektu, który będzie miał wspólną funkcjonalność. Dołączając metody do prototypu, możesz zaoszczędzić na powielaniu metod tworzonych dla każdejnew
instancji. Jednak po dołączeniu metody do elementuprototype
wszystkie wystąpienia będą miały dostęp do tych metod.Powiedzmy, że masz
Car()
klasę / obiekt bazowy .function Car() { // do some car stuff }
następnie tworzysz wiele
Car()
instancji.var volvo = new Car(), saab = new Car();
Teraz wiesz, że każdy samochód będzie musiał jeździć, włączać itd. Zamiast dołączać metodę bezpośrednio do
Car()
klasy (która zajmuje pamięć dla każdej utworzonej instancji), możesz zamiast tego dołączyć metody do prototypu (tworzenie tylko metod raz), dając tym samym dostęp do tych metod zarówno nowemu, jakvolvo
isaab
.// just mapping for less typing Car.fn = Car.prototype; Car.fn.drive = function () { console.log("they see me rollin'"); }; Car.fn.honk = function () { console.log("HONK!!!"); } volvo.honk(); // => HONK!!! saab.drive(); // => they see me rollin'
źródło
Car.prototype = { ... }
musiałby przyjść przed wywołaniem a,new Car()
jak pokazano w tym jsfiddle: jsfiddle.net/mxacA . Jeśli chodzi o twój argument, byłby to właściwy sposób: jsfiddle.net/Embnp . Zabawne jest to, że nie pamiętam odpowiedzi na to pytanie =)Umieść funkcje na obiekcie prototypowym, gdy masz zamiar utworzyć wiele kopii określonego rodzaju obiektu i wszystkie muszą mieć wspólne zachowania. W ten sposób zaoszczędzisz trochę pamięci, mając tylko jedną kopię każdej funkcji, ale to tylko najprostsza korzyść.
Zmiana metod w obiektach prototypowych lub dodanie metod powoduje natychmiastową zmianę charakteru wszystkich wystąpień odpowiedniego typu (typów).
To, dlaczego robisz te wszystkie rzeczy, jest głównie funkcją twojego własnego projektu aplikacji i rodzajów rzeczy, które musisz zrobić w kodzie po stronie klienta. (Zupełnie inną historią byłby kod na serwerze; o wiele łatwiej wyobrazić sobie wykonywanie tam kodu „OO” na dużą skalę).
źródło
Jeśli wyjaśnię terminem opartym na klasie, to Person jest klasą, walk () jest metodą prototypową. Więc walk () będzie istniał dopiero po utworzeniu instancji nowego obiektu z this.
Więc jeśli chcesz utworzyć kopie obiektu takiego jak Osoba, możesz utworzyć wielu użytkowników Prototyp jest dobrym rozwiązaniem, ponieważ oszczędza pamięć przez współdzielenie / dziedziczenie tej samej kopii funkcji dla każdego obiektu w pamięci.
Natomiast statyczność nie jest tak wielką pomocą w takim scenariuszu.
function Person(){ this.name = "anonymous"; } // its instance method and can access objects data data Person.prototype.walk = function(){ alert("person has started walking."); } // its like static method Person.ProcessPerson = function(Person p){ alert("Persons name is = " + p.name); } var userOne = new Person(); var userTwo = new Person(); //Call instance methods userOne.walk(); //Call static methods Person.ProcessPerson(userTwo);
Więc z tym bardziej przypomina metodę instancji. Podejście obiektu jest podobne do metod statycznych.
https://developer.mozilla.org/en/Introduction_to_Object-Oriented_JavaScript
źródło