Dziedziczenie w JavaScript – część 2

Jak wygląda obiekt?

Chciałabym wam opowiedzieć o tym jak wygląda dziedziczenie w JavaScript i po co jest nam w ogóle potrzebne, ale zanim do tego dojdziemy musimy porozmawiać o tym jak wygląda obiekt. Także ta część powinna was dobrze wprowadzić w podstawy.

Jak wiecie tłumacząc różne rzeczy zawsze staram się szukać jakiejś metafory, która pomoże w zrozumieniu trudnych zagadnień. Tym razem również znalazłam coś ciekawego do opisania dziedziczenia prototypowego – Zajrzyj do wpisu Dziedziczenie w JavaScript – część 1

Dziedziczenie prototypowe – podstawy

Wiesz już, że każdy obiekt w JavaScript ma jakiegoś przodka, że obiekty są ze sobą połączone. Podejrzyjmy zatem jak to wygląda w kodzie.

Czym jest obiekt ?

Obiekt to kolekcja kluczy i wartości.

Tworzymy obiekt, nadajemy mu odpowiednie atrybuty i jeśli spróbujemy je wypisać w konsoli, to naszym oczom ukaże się jakaś epopeja narodowa.

Skąd ten obiekt ma tyle rzeczy w sobie? Przecież ich nie definiowaliśmy?

Otóż każdy obiekt w JavaScript ma ustawioną podczas tworzenia wewnętrzną właściwość oznaczaną w specyfikacji jako [[Prototype]].
I jest to odwołanie do innego obiektu – tak po prostu. W Chrome jeśli chcielibyśmy podejrzeć tą właściwość znajdziemy ją pod nazwą  __proto__.


Dlaczego mamy dwie nazwy do opisu tego samego?

Czym się różni [[Prototype]] od __proto__?


Otóż jak wiecie różne przeglądarki są wyposażone w różne silniki interpretujące JavaScript. Silniki te nie zawsze są ze sobą kompatybilne. Właściwość __proto__ spotkamy np. w silniku V8 , ale w innych silnikach jego implementacja może nie być taka sama. Spójrzcie na listę silników ECMAScript  jest ich sporo, prawda? Morał z tego taki, że nie jest polecane bezpośrednie odnoszenie się do atrybutu __proto__.  Możemy go podejrzeć w konsoli, ale nie wykorzystujemy tego w kodzie.

[[Prototype]] to odniesienie do innego obiektu – ale do jakiego?


Nasz obiekt alien ma 3 atrybuty stworzone przez nas oraz własność [[Prototype]]  dodaną domyślnie podczas tworzenia obiektu.
Poprzez [[Prototype]] jest połączony z innym obiektem. Jakim ? No właśnie, to kolejna zagadka, spójrzmy na  kolejny obrazek.

Obiekt alien jest połączony, tak jak inne obiekty wbudowane z tym tajemniczym obiektem. Będzie to Ojciec Wszystkich Ojców – czyli wszystkie obiekty w JavaScript będą z nim połączone.  (Więcej o obiektach wbudowanych w tym linku. )

Czym jest Prototype?

Zanim poznamy czym jest ten obiekt czyli Ojciec Wszystkich Ojców poznajmy FUNCTION, specyficzny obiekt wbudowany.

Wszystkie funkcje w JavaScript posiadają w swoich atrybutach jeszcze jeden „dziwny” prototyp i jest to coś innego niż poznane przed chwilą __proto__.

Stwórzmy zatem funkcję i przyjrzyjmy się jej z bliska.

Jeśli podejrzymy sobie w konsoli Chrome, jak wygląda funkcja, zauważymy że rzeczywiście posiada [[Prototype]] oraz dodatkowo jeszcze jeden atrybut prototype.

  • [[Prototype]] – to już wiemy – jest to odniesienie do innego obiektu – zaraz sprawdzimy do jakiego.
  • prototype – to odniesienie do pustego obiektu.

Gdzie nas odnoszą te dziwne atrybuty? Spójrzmy na kolejny obrazek.

 

Rzeczywiście, atrybut prototype (ten na czerwono na obrazku wyżej) odnosi nas do innego pustego obiektu, który jako, że też jest obiektem, posiada własność [[Prototype]] odnoszącą go dalej, natomiast atrybut [[Prototype]] – funkcji Alien – odnosi nas do obiektu wbudowanego FUNCTION (Jasna sprawa, przecież to funkcja).

Ojciec Wszystkich Ojców

Wreszcie nadszedł czas na poznanie Ojca Wszystkich Ojców, czyli obiekt, z którym połączone są wszystkie inne obiekty w JavaScript.

W JavaScript mamy specjalny obiekt wbudowany – Object.
Sam Object to „konstruktor”, za pomocą którego możemy tworzyć wszystkie typy obiektów – jest po prostu funkcją, ale to jeszcze nie on jest naszym bohaterem.

Jako, że Object jest funkcją, ma w atrybutach dostęp do obiektu Object.prototype, który przechowuje wszystkie potrzebne dla innych obiektów właściwości. To właśnie do Object.prototype mają dostęp wszystkie obiekty w JavaScript.

Czyli kto jest Ojcem Wszystkich Ojców w JavaScript? Odpowiedź: Oczywiście Object.prototype, nie Object.

Jeśli wypiszemy sobie Object.prototype w konsoli, zobaczymy wszystkie właściwości , które miał na początku dostępny obiekt alien.

Jak to możliwe?
Dzięki połączeniom pomiędzy obiektami mogą one korzystać ze swoich właściwości – „pożyczając je”.  Obiekt alien jest automatycznie połączony z Object.prorotype, z którego właściwości może korzystać.  Takie połączenia między obiektami są często określane jako łańcuch połączeń.

Zobaczmy jeszcze raz połączenie obiektu Alien oraz obiektów wbudowanych.

 

Podsumowanie części I

Czyli mamy 3 pojęcia związane z  prototypami w JavaScript:
__proto__  – to wskazanie na inny obiekt, każdy obiekt posiada taki atrybut, zwykłe obiekty są połączone z Object.prototype;
[[Prototype]] – to samo co __proto__, tylko tak jest zapisane w specyfikacji EcmaScript;
prototype – to również wskazanie na inny obiekt,  pusty (można do niego dopisywać różne atrybuty),  posiadają go tylko funkcje.

Jak z tego korzystać? Jak manipulować połączeniami ? Po co ktoś zaprojektował taką masakrę połączeń ? Zapraszam do kolejnego wpisu –  Dziedziczenie w JavaScript – część 3

Metaforę z obcą planetą i jej mieszkańcami wymyśliłam przygotowując się do wystąpnienia na konferencji Programistok  – 7 października 2017 roku.

 

Komentarze
 

Agata Malec-Sromek

 

Dodaj komentarz