• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Jak przypisać prototyp konstruktora do innego konstruktora?

0 głosów
135 wizyt
pytanie zadane 10 kwietnia 2020 w JavaScript przez maslokeeper01 Użytkownik (620 p.)

Witam, 

Uczę się obiektówki w JS i mam stworzone dwa konstruktory:

function Footballer(first, surname, club, strongFoot){
    this.first=first;
    this.surname=surname;
    this.club=club;
    this.foot=strongFoot;
}

function Goalkeeper(first, surname, club, defStyle){
    this.first=first;
    this.surname=surname;
    this.club=club;
    this.defStyle=defStyle;
    }

Jednocześnie dla metod dokonałem zmian w prototypie konstruktora Footballer:
 

//change club
    Footballer.prototype.changeClub = function(newClub){
        return `${this.first} ${this.surname} moves to ${this.club=newClub}.`;
    }

//get some informations about the player
    Footballer.prototype.informations = function(){
        return `${this.first} ${this.surname}, plays in ${this.club}.`;
    }

Dla obiektów stworzonych przez oba konstruktory chciałbym mieć dostęp do powyższego prototypu, ale przy tworzeniu obiektu z użyciem new Goalkeeper() ani Object.create(), ani Object.assign() nie działa tak, jak bym chciał. Widać ponadto, że oba konstruktory zawierają powtarzające się właściwości, a zapis obydwu konstruktorów można skrócić, stąd pytanie - które z narzędzi JavaScriptu pozwala na przypisanie dwóm konstruktorom tego samego prototypu? Lub chociaż pobrać prototyp jednego konstruktora (Footballer) i przypisać go do drugiego (Goalkeeper)?

Z góry dziękuję za pomoc.

komentarz 10 kwietnia 2020 przez Comandeer Guru (562,680 p.)
Co to znaczy "nie działa tak, jakbym chciał"?
komentarz 10 kwietnia 2020 przez maslokeeper01 Użytkownik (620 p.)

Chcę uzyskać dostęp do prototypu Footballer dla obiektów stworzonych z użyciem Goalkeeper. Object.create() tego nie umożliwił, prawdopodobnie dlatego, że użyłem złej składni, ale chce się dowiedzieć, czy nie ma jakiejś lepszej metody.

1 odpowiedź

0 głosów
odpowiedź 10 kwietnia 2020 przez Comandeer Guru (562,680 p.)
wybrane 10 kwietnia 2020 przez maslokeeper01
 
Najlepsza

Przy takiej składni najłatwiej jest zrobić po prostu:

Goalkeeper.prototype = new Footballer();

Chociaż

Goalkeeper.prototype = Object.create( Footballer.prototype );

też powinno dać radę.

komentarz 10 kwietnia 2020 przez ScriptyChris Mędrzec (171,440 p.)

A dlaczego nie w ten sposób?

Goalkeeper.prototype = Footballer.prototype;

które z narzędzi JavaScriptu pozwala na przypisanie dwóm konstruktorom tego samego prototypu?

Albo, jeśli oba konstrukoury mają być połączone z tym samym prototypem, to może w ten sposób?

const sharedPrototype = {
    changeClub() {},
    informations() {}
};

Goalkeeper.prototype = sharedPrototype;
Footballer.prototype = sharedPrototype;

 

komentarz 10 kwietnia 2020 przez Comandeer Guru (562,680 p.)

A dlaczego nie w ten sposób?

Bo w tym momencie każda zmiana wprowadzona w Goalkeeper będzie też widoczna w Footballer, a raczej nie tak to powinno działać. Raczej powinno to działać w drugą stronę, żeby osiągnąć dziedziczenie. 

komentarz 10 kwietnia 2020 przez maslokeeper01 Użytkownik (620 p.)
	
Goalkeeper.prototype = Footballer.prototype;

To nie działa jak zwykła operacja przypisania? Dlaczego?

komentarz 10 kwietnia 2020 przez Comandeer Guru (562,680 p.)
No właśnie działa aż za dobrze ;) Bo w tym momencie te dwie klasy będą miały dokładnie ten sam prototyp – a raczej nie tego oczekujemy.
komentarz 11 kwietnia 2020 przez ScriptyChris Mędrzec (171,440 p.)

@maslokeeper01, obiektówkę JSa szczegółowo tłumaczy Kyle Simpson w swojej książce You Don't Know JS:

https://github.com/getify/You-Dont-Know-JS/blob/1st-ed/this%20&%20object%20prototypes/README.md#you-dont-know-js-this--object-prototypes

Propozycja, którą podałem (bezpośrednie przypisanie prototypu jednego konstruktora do prototypu drugiego konstruktora) jest właściwie złą praktyką. Opisuje to poniższy rozdział:

https://github.com/getify/You-Dont-Know-JS/blob/1st-ed/this%20%26%20object%20prototypes/ch5.md#prototypal-inheritance

Poniższy sposób też jest odradzany, ze względu na możliwe efekty uboczne:

Goalkeeper.prototype = new Footballer();

Cytując:

Bar.prototype = new Foo() does in fact create a new object which is duly linked to Foo.prototype as we'd want. But, it uses the Foo(..) "constructor call" to do it. If that function has any side-effects (such as logging, changing state, registering against other objects, adding data properties to this, etc.), those side-effects happen at the time of this linking (and likely against the wrong object!), rather than only when the eventual Bar() "descendants" are created, as would likely be expected.

Z podanych opcji najlepszą jest:

Goalkeeper.prototype = Object.create( Footballer.prototype );

Jeśli uczysz się obiektówki w "starszej" wersji (ES5), to warto żebyś też poznał składnię class (wprowadzoną od ES6) i żebyś był świadom, że ta składnia nadal opiera się o mechanizm prototypów (jest tzw. cukrem składniowym), mimo że nazewnictwo sugeruje bliższy związek z obiektówką z innych języków programowania. Po więcej szczegółów ponownie odsyłam do wspomnianej książki:

https://github.com/getify/You-Dont-Know-JS/blob/1st-ed/this%20%26%20object%20prototypes/ch6.md

https://github.com/getify/You-Dont-Know-JS/blob/1st-ed/this%20%26%20object%20prototypes/apA.md

komentarz 11 kwietnia 2020 przez Comandeer Guru (562,680 p.)
Powiedzmy sobie szczerze: jeśli konstruktor ma efekty uboczne, to jest źle zaprojektowany i to w tym leży błąd, nie w użyciu instancji jako prototypu.

Jedyny przypadek, gdzie faktycznie może to być niewskazane, to przypisywanie czegoś do this w konstruktorze.
komentarz 11 kwietnia 2020 przez ScriptyChris Mędrzec (171,440 p.)
Ok, ale jeśli jedno podejście jest podatne na efekty uboczne, a inne nie, to lepiej wybrać bezpieczniejsze. Chyba, że to pierwsze oferuje więcej możliwości, a przed efektami ubocznymi można się zabezpieczyć (choćby lepiej projektując konstruktor, jak wspomniałeś).
komentarz 11 kwietnia 2020 przez Comandeer Guru (562,680 p.)

Ogólnie nie polecam podejścia, które sugeruje Simpson w swojej książce. To jest tak naprawdę jedyny prominentny twórca w świecie JS-a, który promuje OLOO, nikt inny tego nie robi.

Z tego też powodu stwierdzenie typu:

When compared to the simplicity of OLOO-style code and behavior delegation (see Chapter 6), which embrace [[Prototype]] rather than hide from it, classes stand out as a sore thumb in JS.

brzmi po prostu śmiesznie. Dodatkowo Simpson udaje, że nie istnieje dziedziczenie prototypowe, uparcie nazywając to delegowaniem zachowań czy linkowaniem prototypów:

In Chapter 5, we addressed the [[Prototype]] mechanism in detail, and why it's confusing and inappropriate (despite countless attempts for nearly two decades) to describe it as "class" or "inheritance".

Jeśli cały świat JS mówi o dziedziczeniu i taką terminologią posługuje się nawet oficjalna specyfikacja, to stawianie się w roli – jak Simpson sam o sobie mówi (np. w bio na Twitterze) – teologa JS-a jest co najmniej śmieszne.

Co więcej stwierdzenia pokroju

In fact, JavaScript is almost unique among languages as perhaps the only language with the right to use the label "object oriented", because it's one of a very short list of languages where an object can be created directly, without a class at all.

całkowicie zaprzeczają temu, co kryje się pod pojęciem OOP.  Wystarczy wziąć nawet definicję z Wikipedii:

Object-oriented programming (OOP) is a programming paradigm based on the concept of "objects", which can contain data, in the form of fields (often known as attributes or properties), and code, in the form of procedures (often known as methods).

Ta definicja całkowicie pomija sposób uzyskiwania obiektów oraz ich prezentacji. Z tego też powodu języki typowo klasowe (Java, C# itd.) są w takim samym stopniu obiektowe jak JS, tak długo, jak można w nich reprezentować dane w postaci obiektów oraz te dane przy pomocy tych obiektów transformować.

I to po raz kolejny pokazuje, jak Simpson nagina czy wręcz całkowicie zmienia ogólnie uznane pojęcia, by dostosować je do swojej wizji JS-a. Zresztą w innych jego książkach też to widać, gdy np. usilnie nazywa interpretację JS-a kompilacją (sic!).

Zresztą pisząc o obiektach Simpson cały czas omija OFICJALNE nazewnictwo zawarte w specyfikacji, np. mówi o funkcjach "klasach" zamiast konstruktorach. Innymi słowy: Simpson tonem swojej książki sugeruje, jakoby specyfikacja opisywała nieistniejącą rzeczywistość:

There's a peculiar kind of behavior in JavaScript that has been shamelessly abused for years to hack something that looks like "classes".

Dalej:

Note: This convention is so strong that many JS linters actually complain if you call new on a method with a lowercase name, or if we don't call new on a function that happens to start with a capital letter. That sort of boggles the mind that we struggle so much to get (fake) "class-orientation" right in JavaScript that we create linter rules to ensure we use capital letters, even though the capital letter doesn't mean anything at all to the JS engine. 

"Ja, pan wszystkowiedzący, wiem doskonale, jak to powinno wyglądać" – przecież to jest dokładnie ten ton. Simpson pokazuje środkowy palec całemu środowisku JS, które przyjęło konkretne konwencje, by lepiej organizować kod. Simpson się na to wypina, agresywnie próbując dowieść słuszności swojej wizji – nawet pomimo tego, że jest ona sprzeczna ze specyfikacją ECMAScript, co można obiektywnie dowieść.

Dalej, zrównywanie Object.setPrototypeOf z Object.create jest błędne, ponieważ te metody robią dwie różne rzeczy. Pierwsza tak naprawdę modyfikuje w locie prototyp konkretnego obiektu, druga – tworzy obiekt o podanym prototypie. Jedna funkcja ma efekty uboczne, druga nie. Co więcej, jeśli chodzi o wydajność, to niekoniecznie to, co sugeruje Simspon jest prawdą – prawdopodobnie jest wręcz odwrotnie.

Dalej, sugerowanie, że instanceof ma sprawdzać powiązanie między obiektami, jest całkowicie błędne. Ten operator naprawdę sprawdza, czy dana funkcja była konstruktorem konkretnego obiektu – a więc robi dokładnie to, co Simpson w swojej książce wyśmiewa.

Wszystkie pojęcia, którymi posługuje się Simpson, mają sens tylko i wyłącznie przy pisaniu kodu w sposób, w jaki proponuje to Simpson. Tylko że praktycznie nikt tak programów nie pisze. A to sprawia, że książka Simpsona jest po prawdzie szkodliwa i raczej powinna się nazywać You don't know MY JS.

Podobne pytania

+1 głos
2 odpowiedzi 179 wizyt
pytanie zadane 26 października 2019 w C i C++ przez AuriattaDev Początkujący (390 p.)
0 głosów
1 odpowiedź 94 wizyt
pytanie zadane 10 kwietnia 2020 w JavaScript przez maslokeeper01 Użytkownik (620 p.)

86,427 zapytań

135,187 odpowiedzi

300,309 komentarzy

57,184 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto dwie polecane książki warte uwagi. Pełną listę znajdziesz tutaj.

...