Obiekty - jak to działa w Javascript

Zanim przejdziemy do kolejnych tematów, musimy sobie wyjaśnić jak w Javascript w ogóle te wszystkie obiekty działają.

Pisałem Ci już kilka razy, że w JavaScript praktycznie wszystko jest obiektem.
Gdy używasz na przykład obiektu Math, działasz na obiekcie.
Gdy odwołujesz się do właściwości length tablicy, odwołujesz się do właściwości length obiektu tablicy (bo tablice to też obiekty).
Używasz window? - używasz obiektu, który ma metody i właściwości. Używasz Date? - to też obiekt - który ma metody i właściwości. Pobierasz coś ze strony? Pobierasz obiekty, które mają metody i właściwości...

No dobrze. Stwórzmy więc na chwilę prosty obiekt i odpalmy na nim metody:


const user = {
    name: "Marcin",
    height: 184,

    sayName : function() {
        console.log(this.name);
    }
}

user.sayName();
user.toString();

Ale co się stało? Przecież nasz obiekt nie ma żadnej metody toString().
A konsola debugera nie pokazała żadnego błędu.

Zadziałał tutaj mechanizm dziedziczenia, na którym bazują wszystkie obiekty w Javascript.

Po zbadaniu naszego obiektu w konsoli (zrób to teraz, wypisałem go w konsoli dla Ciebie) debugera zobaczysz w nim właściwość __proto__. Jest to właściwość dodawana przez JavaScript automatycznie każdemu obiektowi. JavaScript dodał za nas do obiektu mniej więcej coś takiego:


const user = {
    //tu nasze właściwości i meotdy

    __proto__ = {...to jest prototyp obiektu...}
}

__proto__ to właściwość, która wskazuje na prototyp, na którym opiera się dany obiekt.
Każdy obiekt w JavaScript zbudowany jest na bazie jakiegoś prototypu - czyli obiektu wzorca, który zawiera metody i właściwości, które dany obiekt może wykorzystywać. Nawet jak robisz pojedynczą instancję (jeden obiekt - tak jak robiliśmy powyżej) to jest ona połączona z jakimś obiektem wzorca za pomocą właśnie __proto__.

Jeżeli wywołujemy jakąś metodę lub właściwość danego obiektu, Javascript początkowo szuka ich bezpośrednio w instancji danego obiektu. Jeżeli ich tam nie znajdzie, za pomocą właściwości __proto__ (która istnieje w każdym obiekcie) przechodzi do prototypu obiektu - czyli obiektu, który opisuje ogólnie wygląd obiektów danego typu (np. Array, String, Date itp.). Szuka w takim obiekcie-prototypie danej metody.

Skoro prototyp jest obiektem, to także ma swoje __proto__. Jeżeli JavaScript nie znajdzie w tym prototypie szukanej metody, korzystając z jego __proto__ dalej przechodzi do nadrzędnego prototypu i tak pnie się w górę, aż dojdzie do najwyższego prototypu - rodzica wszelkich obiektów - Object, na bazie którego zbudowane są wszelkie obiekty w JavaScript. Prototyp Object właściwości __proto__ już nie ma, więc JavaScript nie ma gdzie iść w górę.

W naszym przypadku nasz obiekt user nie ma metody toString(), ale gdy badając go w konsoli rozwiniemy jego zawartość zobaczymy, że ma __proto__. Gdy rozwiniemy i tą właściwość zobaczymy, że wskazuje on na prototyp naszego obiektu. Prototyp ten to prototyp wszelakich Obiektów - czyli prototyp Object, który już ma tą metodę (dlatego metodę toString() ma każdy obiekt w JavaScript).
JavaScript nie znalazł ten jetody w naszym obiekcie, więc wziął sobie góry hierarchii. Nasz malutki obiekt pożyczył więc sobie metodę od wielkiego mistrza Object. Wielki zaszczyt...

prototyp z debugera 1

Mega siatka

Z całego powyższego opisu wyłania się nam struktura obiektów w JavaScript, które stanowią rodzaj powiązanej pajęczej sieci.

Na samej górze jest grand master (on tak się nie nazywa!) - prototyp wszystkich obiektów. Wszelkie obiekty prędzej czy później na niego wskazują za pomocą __proto__, co oznacza, że każdy obiekt w JavaScript może korzystać z jego metod i właściwości.

Jeżeli dane instancje obiektów są tylko pojedynczymi instancjami (nie zostały stworzone na bazie żadnego konstruktora typu Array, Data(), naszego konstruktora itp.), to ich __proto__ wskazuje na właśnie ten prototyp Object.

Jeżeli nasze obiekty zostały stworzone na bazie konstruktora, to wszystkie one wskazują na wspólny obiekt prototypu (Array, Data, NaszKonstruktor), w którym właściwość o nazwie __proto__ wskazuje na wyższy prototyp. I tak w koło aż do "Wielkiego Żółwia"... znaczy się prototypu Object - który też jest obiektem.

Zobacz w powiększeniu Mega siatka połączeń