Obecnie przechodzę z Java do Javascript i jest mi trochę trudno wymyślić, jak rozszerzać obiekty tak, jak chcę.
Widziałem kilka osób w Internecie, które używają metody zwanej rozszerzaniem obiektu. Kod będzie wyglądał następująco:
var Person = {
name : 'Blank',
age : 22
}
var Robot = Person.extend({
name : 'Robo',
age : 4
)}
var robot = new Robot();
alert(robot.name); //Should return 'Robo'
Czy ktoś wie, jak to działa? Słyszałem, że musisz pisać
Object.prototype.extend = function(...);
Ale nie wiem, jak sprawić, by ten system działał. Jeśli nie jest to możliwe, pokaż mi inną alternatywę, która rozszerza obiekt.
extend
funkcja, ustawiłem tutaj przykład: jsfiddle.net/k9LRdOdpowiedzi:
Chcesz „dziedziczyć” po prototypowym obiekcie osoby:
źródło
Person()
wywoływany jest konstruktor, kiedy to robisznew Robot()
? Wydaje mi się, że powinieneś wywołać ten konstruktor klasy bazowej zamiast robićthis.name = name;
wRobot()
konstruktorze ...Person.apply(this, arguments);
. Byłoby też lepiej użyćRobot.prototype = Object.create(Person.prototype);
zamiastnew Person();
.Świat bez słowa kluczowego „nowe”.
I prostsza "prozaiczna" składnia z Object.create ().
* Ten przykład został zaktualizowany dla klas ES6.
Po pierwsze, pamiętaj, że JavaScript jest językiem prototypowym . Nie jest oparta na klasach. W związku z tym pisanie w formie prototycznej ujawnia jego prawdziwą naturę i może być bardzo proste, przypominające prozę i potężne.
TLDR;
Nie, nie potrzebujesz konstruktorów, żadnych
new
instancji ( przeczytaj, dlaczego nie powinieneś ich używaćnew
), niesuper
, żadnych zabawnych zabawnych__construct
. Po prostu tworzysz obiekty, a następnie rozszerzasz je lub przekształcasz.( Jeśli znasz metody pobierające i ustawiające, zobacz sekcję „Dalsze czytanie”, aby zobaczyć, w jaki sposób ten wzorzec zapewnia bezpłatne metody pobierające i ustawiające w sposób, do którego pierwotnie był przeznaczony JavaScript , i jakie one są potężne ).
Składnia podobna do prozy: Prototyp podstawowy
Na pierwszy rzut oka wygląda bardzo czytelnie.
Rozszerzenie, tworząc potomka
Person
* Prawidłowe terminy to
prototypes
i ichdescendants
. Nie maclasses
i nie ma takiej potrzebyinstances
.Jednym ze sposobów zapewnienia „domyślnego” sposobu tworzenia
descendant
jest dołączenie#create
metody:Poniższe sposoby mają niższą czytelność:
Porównaj z „klasycznym” odpowiednikiem:
Czytelność kodu przy użyciu stylu „klasycznego” nie jest dobra.
Klasy ES6
Wprawdzie niektóre z tych problemów są eliminowane przez klasy ES6, ale nadal:
Rozgałęzienie podstawowego prototypu
Dołącz metody unikalne dla
Robot
Sprawdzam dziedziczenie
Masz już wszystko, czego potrzebujesz! Bez konstruktorów, bez instancji. Czysta, klarowna proza.
Dalsza lektura
Zapisywalność, konfigurowalność oraz bezpłatne metody pobierające i ustawiające!
Aby uzyskać bezpłatne metody pobierające i ustawiające lub dodatkową konfigurację, możesz użyć drugiego argumentu Object.create (), znanego również jako propertiesObject. Jest również dostępny w # Object.defineProperty i # Object.defineProperties .
Aby zilustrować, jak potężne jest to, załóżmy, że chcemy, aby wszystko
Robot
było ściśle wykonane z metalu (przezwritable: false
) i ujednolicićpowerConsumption
wartości (za pomocą pobierających i ustawiających).A wszystkie prototypy
Robot
nie mogą byćmadeOf
czymś innym, ponieważwritable: false
.Miksery (za pomocą # Object. assign) - Anakin Skywalker
Czy wyczuwasz, dokąd to zmierza ...?
Darth Vader otrzymuje metody
Robot
:Wraz z innymi dziwnymi rzeczami:
Cóż, to, czy Darth Vader jest człowiekiem, czy maszyną, jest rzeczywiście subiektywne:
Extra - nieco krótsza składnia z # Object. assign
Najprawdopodobniej ten wzorzec skraca twoją składnię. Ale ES6 # Object. assign może jeszcze bardziej skrócić (aby użyć polyfill w starszych przeglądarkach, zobacz MDN w ES6 ).
źródło
Object.assign(Robot, {a:1}
jest dobrą alternatywą dla twojejextend()
metody? 2) Jak nadpisaćgreet()
metodę, aby zwracała ten sam tekst, ale z dopiskiem „a greet override”?#Object.assign
wygląda na dobrą alternatywę. Ale obsługa przeglądarek jest niższa. 2) Użyjesz__proto__
właściwości obiektu, aby uzyskać dostęp do funkcji powitania jego prototypu. następnie wywołujesz prototypową funkcję greet z przekazanym zakresem wywoływanego. w tym przypadku funkcja była dziennikiem konsoli, więc nie można jej „dopisać”. Ale w tym przykładzie myślę, że masz dryf.skywalker.greet = function() { this.__proto__.greet.call(this); console.log('a greet override'); }
Jeśli jeszcze nie wymyśliłeś sposobu, użyj właściwości asocjacyjnej obiektów JavaScript, aby dodać funkcję rozszerzającą do funkcji,
Object.prototype
jak pokazano poniżej.Możesz następnie użyć tej funkcji, jak pokazano poniżej.
źródło
Inne podejście: Object.create
Zgodnie z odpowiedzią @osahyoun, uważam, że następujące sposoby są lepszym i wydajnym sposobem „dziedziczenia” z prototypowego obiektu Person:
Utwórz nowe instancje:
Teraz, używając Object.create :
Sprawdź również dokumentację MDN .
źródło
name
parametru do konstruktora nadrzędnego, na przykład: jsfiddle.net/3brm0a7a/3 (różnica jest w linii # 8)W ES6 możesz używać operatora rozszerzania, takiego jak
Aby uzyskać więcej informacji, zobacz link, Składnia MDN -Spread
Stara odpowiedź:
W ES6 istnieje
Object.assign
możliwość kopiowania wartości właściwości. Użyj{}
jako pierwszego parametru, jeśli nie chcesz modyfikować obiektu docelowego (pierwszy przekazany parametr).Aby uzyskać więcej informacji, zobacz link, MDN - Object. assign ()
W przypadku, gdy potrzebujesz Polyfill dla ES5 , link również go oferuje. :)
źródło
A rok później mogę powiedzieć, że jest jeszcze jedna miła odpowiedź.
Jeśli nie podoba ci się sposób, w jaki działa prototypowanie w celu rozszerzenia na obiekty / klasy, spójrz na to: https://github.com/haroldiedema/joii
Szybki przykładowy kod możliwości (i wiele więcej):
źródło
Osoby, które wciąż walczą o proste i najlepsze podejście, możesz wykorzystać
Spread Syntax
do rozbudowy obiektu.Uwaga: Pamiętaj, że pierwszeństwo ma nieruchomość położona najdalej na prawo. W tym przykładzie
person2
jest po prawej stronie, więcnewObj
będzie zawierał nazwę Robo .źródło
Możesz rozważyć użycie biblioteki pomocniczej, takiej jak underscore.js , która ma własną implementację
extend()
.Jest to również dobry sposób uczenia się, patrząc na jego kod źródłowy. Uwagami strona kod źródłowy jest bardzo przydatna.
źródło
_.extend()
działa underscore.js sprawia, że jego funkcjonalność jest całkiem jasna: lostechies.com/chrismissal/2012/10/05/...Mozilla 'ogłasza' obiekt rozszerzający ECMAScript 6.0:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/extends
UWAGA: Jest to technologia eksperymentalna, część propozycji ECMAScript 6 (Harmony).
Ta technologia jest dostępna w Gecko (Google Chrome / Firefox) - wersje nocne 03/2015.
źródło
W większości projekcie istnieją pewne realizacja obiektu rozszerzenie: podkreślenia, jQuery, lodash: przedłużyć .
Istnieje również czysta realizacja JavaScript, który jest częścią ECMAScript 6: Object.assign : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
źródło
Następnie:
Aktualizacja 01/2017:
Proszę, zignoruj moją odpowiedź z 2015 roku, ponieważ JavaScript obsługuje teraz
extends
słowo kluczowe od ES6 (Ecmasctipt6)- ES6:
- ES7:
źródło
new ParentClass()
przed nadpisaniem konstruktora, wykonałeś już konstruktora nadrzędnego. Nie sądzę, żeby to było właściwe zachowanie, jeśli mnie zapytasz ...Podsumowanie:
Javascript używa mechanizmu, który nazywa się dziedziczeniem prototypowym . Dziedziczenie prototypowe jest używane podczas wyszukiwania właściwości obiektu. Kiedy rozszerzamy właściwości w javascript, dziedziczymy te właściwości z rzeczywistego obiektu. Działa w następujący sposób:
myObj.foo
LubmyObj['foo']
), silnik JS najpierw szuka tej właściwości w samym obiekcieKiedy chcemy rozszerzyć obiekt w javascript, możemy po prostu połączyć ten obiekt w łańcuch prototypów. Jest wiele sposobów, aby to osiągnąć, opiszę 2 powszechnie stosowane metody.
Przykłady:
1.
Object.create()
Object.create()
jest funkcją, która przyjmuje obiekt jako argument i tworzy nowy obiekt. Obiekt przekazany jako argument będzie prototypem nowo utworzonego obiektu. Na przykład:2. Jawne ustawienie właściwości prototypu
Podczas tworzenia obiektów za pomocą funkcji konstruktora możemy ustawić właściwości add do właściwości obiektu prototypowego. Obiekty, które są tworzone z funkcji konstruktora przy użyciu
new
słowa kluczowego, mają swój prototyp ustawiony na prototyp funkcji konstruktora. Na przykład:źródło
Możesz to po prostu zrobić za pomocą:
Następnie użyj go tak:
To dobrze skutkuje:
źródło
PROSZĘ DODAĆ POWÓD DO DOWNVOTE
Nie ma potrzeby korzystania z żadnej zewnętrznej biblioteki do rozszerzenia
W JavaScript wszystko jest obiektem (poza trzema prymitywnymi typami danych, a nawet one są automatycznie zawijane obiektami w razie potrzeby). Ponadto wszystkie obiekty są zmienne.
dzięki ross harmes, dustin diaz
źródło
Spowoduje to, że rozszerzone właściwości utworzą nowy obiekt z prototypami parametrów obiektu bez zmiany przekazanego obiektu.
Ale jeśli chcesz rozszerzyć obiekt bez modyfikowania jego parametrów, możesz dodać do niego extensionProperty.
źródło
Prototypowanie to fajny sposób, ale prototyp jest czasami dość niebezpieczny i może prowadzić do błędów. Wolę zamknąć to w obiekcie podstawowym, tak jak robi to Ember.js z Ember.Object.extend i Ember.Object.reopen. To jest znacznie bezpieczniejsze w użyciu.
Stworzyłem streszczenie, w jaki sposób można skonfigurować coś podobnego do tego, czego używa Ember.Object.
Oto link: https://gist.github.com/WebCloud/cbfe2d848c80d4b9e9bd
źródło
Prototyping is a nice way, but prototype is quite dangerous sometimes and can lead to bugs.
Co przez to rozumiesz? Używanie łańcucha prototypów w JavaScript może prowadzić do błędów? To tak, jakby powiedzieć, że używanie klas w Javie może prowadzić do błędów i nie ma absolutnie żadnego sensu.Object
prototyp, twoja funkcja może mieć taką samą nazwę jak przyszła funkcja JavaScript i spowodować eksplozję kodu, gdy zostanie uruchomiona w przyszłości. Na przykład załóżmy, że dodałeśrepeat()
funkcję doObject
i wywołałeś ją naString
instancjach, a następnie twoje środowisko wykonawcze JavaScript zostało zaktualizowane do ES6?prototype
języka .