prototype proto

W pigułce: prototype vs. __proto__

Ciężka sprawa. Czym się różni prototype od  __proto__? Kilka razy podchodziłam do tego tematu, który okazał się być rzeką szeroką i głęboką. Chciałabym więc przedstawić tylko podstawy prototypów, tak w pigułce. Marzy mi się, że trudny temat nie odstraszy potencjalnych czytelników. Zamiast tego zdecydują się poświęcić 5 minut życia, aby być bogatszymi o dawkę konkretnej javascriptowej teorii. Być może w przyszłości, przy pomyślnych wiatrach, dopiszę część drugą artykułu poszerzając podaną tu wiedzę.

prototype

Zacznijmy od tego, że każda funkcja jest obiektem w JS. A więc może posiadać swoje własności czy metody. I właśnie prototype jest własnością każdej funkcji! Natywną, czyli nie musimy jej sami ustalać. Po prostu każda funkcja automatycznie dostaje własność prototype.

Własność  prototype nie mówi „oto prototyp tej funkcji”.

Własność  prototype mówi: „oto prototyp obiektu stworzonego przez tę funkcję”.

prototypy

Funkcja może być też użyta jako konstruktor. Dzieje się to wtedy, kiedy za pomocą funkcji oraz słowa new tworzymy nowy obiekt.

Kiedy tworzysz nowy obiekt, możesz ustawić jego prototyp (czytaj: skąd ma dziedziczyć własności). Kiedy w kodzie odwołujesz się do jakiejś własności obiektu, najpierw jest ona szukana w danym obiekcie. Jeśli nie jest znaleziona, to wtedy JS kopie dalej i szuka w prototypie obiektu. W razie konieczności jeszcze dalej w prototypie prototypu. Aż do skutku. JS ma na to ładne określenie – prototype chain.

W całym procesie podróży po łańcuchu prototypów, możemy ustalić owe prototypy za pomocą pewnej pseudo własności – __proto__.

__proto__

Wymawiane jako “dunder proto” jako skrót od “double underscore proto”.

Wiemy już, że własność __proto__ jest kluczowa w temacie ustalania łańcucha prototypów. To skąd bierze się jej wartość? Z własności  prototype!

Kiedy tworzymy nowy obiekt za pomocą funkcji konstruktora:

var ChildObject = new ParentObject();

JS szuka w ParentObject własność prototype i kopiuje ją do ChildObject jako… własność __proto__! NIE jako prototype.

Bo przecież po co tworzyć rzeczy proste, logiczne i nudne. Życie musi być zaskakujące!

Więc wiemy, że kiedy obiekt jest tworzony funkcją konstruktorem, jego prototypem, czyli też wartością __proto__ jest wartość prototype funkcji konstruktora.

Przykład:

function Fn() {}
var obj = new Fn();

console.log(obj.__proto__ === Fn.prototype);
// -> true

console.log(obj.__proto__.__proto__=== Object.prototype);
// -> true

console.log(obj.__proto__.__proto__.__proto__ === null);
// -> true

A co z pozostałymi obiektami? Tymi, które nie są stworzone za pomocą funkcji konstruktora? Ich łańcuchy prototypów kończą się zawsze Object.prototype. Zresztą spójrzcie na przykład:

var obj = {};
var arr = [];
function fn() {}

console.log(obj.__proto__ === Object.prototype); 
// -> true
console.log(obj.__proto__.__proto__ === null); 
// -> true
console.log(arr.__proto__ === Array.prototype); 
// -> true
console.log(arr.__proto__.__proto__ === Object.prototype); 
// -> true
console.log(fn.__proto__ === Function.prototype); 
// -> true
console.log(fn.__proto__.__proto__ === Object.prototype); 
// -> true

Ważna uwaga – nie edytuje się własności __proto__. Tak z definicji, tak po prostu. To najczarniejsza z czarnych magii. Co prawda __proto__ zostało ustandaryzowane w ES6, jednak może zostać deprecated na korzyść dla Object.getPrototypeOf().


Podsumowując.

Własność prototype jest wykorzystywana do utworzenia własności __proto__.

Źródła i banki fajnej dodatkowej wiedzy: KLIK!KLIK!KLIK!KLIK!KLIK!.

Artykuły, które mogą Ci się spodobać...

Wpisz hasło, którego szukasz i naciśnij ENTER, aby je wyszukać. Naciśnij ESC, aby anulować.

Dawaj na górę