Sieć połączonych ze sobą żyłek.

Programowanie funkcyjne – Powtórka przed ReactJS #11

Dzisiaj przyjrzymy się, czym tak naprawdę zajmują się koderscy hipsterzy. Programowanie funkcyjne to najpopularniejsza alternatywa dla programowania obiektowego. W ostatnich latach zdobywa coraz większą popularność. Wbrew pozorom wywołanym przez ten hype, samo programowanie funkcyjne nie jest niczym nowym. Ten paradygmat istnieje od dziesięcioleci. Do tej pory był używany przede wszystkim w środowiskach akademickich. Jego popularność wzrosła za sprawą Reacta. Ta biblioteka wykorzystuje wiele fundamentalnych koncepcji programowania funkcyjnego.

(więcej…)

Zestaw narzędzi na biurku

Prototypy i dziedziczenie – Powtórka przed ReactJS #10

Przypuśćmy, że naszym dzisiejszym celem jest usprawnienie masowej produkcji krzeseł.

Dziedziczenie klasowe

Postrzegając ten problem przez pryzmat języków obiektowych zorientowanych na klasy, zanim przejdziemy do wytwarzania, musimy przygotować specyfikację produktu.
Rolę specyfikacji będzie stanowiła klasa Krzesło. Zamieścimy w niej wszystkie właściwości i funkcjonalności krzeseł, które będziemy produkować. Najpierw skupimy się na najprostszym modelu, jaki przychodzi nam do głowy, zostawiając sobie furtkę do dalszych usprawnień w przyszłości.

Front-end, Javascript, Nauka programowania, React

Mając do dyspozycji taki plan, wystarczy wydzielić odpowiednią ilość zasobów i możemy zabierać się do pracy. Wychodzimy z założenia, że każdy egzemplarz powinien być idealnym odzwierciedleniem przygotowanej specyfikacji. Stąd, mówi się, że wyprodukowane przez nas krzesła są instancjami klasy Krzesło.

Jeżeli chcielibyśmy stworzyć nowy model krzesła, nie musimy tracić czasu na tworzenie zupełnie nowej specyfikacji. Krzesła dzielą ze sobą wiele cech charakterystycznych, niezależnie od różnic w szczegółach. Każde z nich będzie miało cztery nogi, siedzenie i oparcie, a jego głównym przeznaczeniem będzie możliwość zajęcia na nim miejsca. Wszystkie te cechy są opisane w naszej klasie Krzesło.

Możemy uznać nasz pierwotny projekt za punkt wyjścia. Wystarczy go skopiować, nanieść na niego innowacyjne zmiany, i voila – mamy do dyspozycji nowy produkt. Taki proces nazywamy dziedziczeniem klasowym.

Dziedziczenie prototypowe

Jeżeli zdecydujemy się na podejście prototypowe, zabierzemy się za ten problem zupełnie inaczej. Wychodzimy z założenia, że proces produkcji pierwszego egzemplarza dostarczy nam know-how, które pozwoli na sprawną produkcję kolejnych. Nie będziemy tracić czasu na tworzenie specyfikacji. Bierzemy materiały, instrukcję z IKEA (lub zaprzyjaźnionego bloga programistycznego) i po chwili jesteśmy posiadaczami prototypu krzesła.

To krzesło, konkretny obiekt, będzie stanowiło wzór dla wszystkich następnych krzeseł.
Takie nastawienie, ignorujące rygor przestrzegania specyfikacji, daje nam możliwość późniejszego nanoszenia modyfikacji. Tworząc kolejne krzesła, interesują nas tylko nowości w stosunku do prototypu. W razie wątpliwości co do własności produktu, wystarczy zerknąć na jego prototyp. Takie odwoływanie się do prototypów, wskazywanie ich za pomocą referencji, nazywamy łańcuchem prototypowym. Wykorzystywanie własności prototypu nazywamy dziedziczeniem prototypowym.

Warto wiedzieć: Słowo kluczowe class pojawiło się w składni języka dopiero za sprawą ES6. Jest to jedynie upiększenie składni, które w ostateczności sprowadza się do wykorzystywania prototypów.

Prototypy w JS

Każdy obiekt w momencie utworzenia otrzymuje ukrytą właściwość [[Prototype]]. Może ona przyjąć dwie wartości: null
lub referencję do obiektu nazywanego prototypem. Jeżeli spróbujemy odwołać się do właściwości, która nie zostanie odnaleziona w obiekcie, silnik będzie kontynuował poszukiwania, w obiekcie wskazywanym przez [[Prototype]].
Jeżeli właściwość zostanie odnaleziona w prototypie, silnik zwróci przypisaną do niej wartość, tak jakby znajdowała się w naszym obiekcie od samego początku.

Podczas swoich poszukiwań silnik nie zatrzymuje się na bezpośrednim prototypie naszego obiektu. Przemierzy on cały łańcuch prototypów. Będzie szukał w prototypie prototypu etc., aż do momentu natrafienia na [[Prototype]] z wartością null.
Domyślnie ostatnim ogniwem łańcucha prototypów jest Object.prototype. Jeżeli wyszukiwana właściwość nie zostanie odnalezionaw w żadnym z przeszukiwanych obiektów, to silnik uraczy nas wartością undefined.

Jak w przypadku wszystkich ukrytych właściwości, nie mamy możliwości bezpośredniej interakcji z [[Prototype]].
Jako interfejs służą nam metody obiektu globalnego Object.
Object.getPrototypeOf(obj) zwraca referencję do [[Prototype]], podczas gdy Object.setProtytypeOf(obj, proto) pozwala ustawić prototyp obj na obiekt proto.

Jeżeli chcemy ustawić prototyp obiektu w momencie jego inicjalizacji, należy wykorzystać Object.create(proto, objectProperties). Ta metoda zwróci nam nowy obiekt z właściwością [[Prototype]] wskazującą na proto.

Czasami zależy nam na sprawdzeniu, czy obiekt posiada swoją prywatną właściwość, czy uzyskuje do niej dostęp z
łańcucha prototypów. W tym wypadku wykorzystuje się metodę Object.hasOwnProperty(obj, prop).

Tyle z suchej teorii, przejdźmy do analizy kodu. Przygotowałem dla Was dwie wersje prostego programu generującego obiekty graczy NBA. Pierwsza z nich jest zaimplementowana w oparciu o wzorzec dziedziczenia prototypowego. Druga wersja zawiera alternatywny wzorzec, delegację zachowań.

Zanim przejdziemy dalej, upewnij się, że rozumiesz, jak działa wskaźnik this w JS. Dodam tylko, że prototypy nie mają żadnego wpływu na wartość tego wskaźnika.

Dziedziczenie prototypowe – analiza wzorca

function Player(name, age, discipline) {
this.name = name;
this.age = age;
this.discipline = discipline;
}

Player.prototype.identify = function() { console.log(`Hello, I'm ${this.name}. I'm ${this.age} and I play ${this.discipline}`); };

function BasketballPlayer(name, age, discipline, team, position) {
Player.call(this, name, age, discipline);
this.team = team;
this.position = position;
}

BasketballPlayer.prototype = Object.create(Player.prototype);

BasketballPlayer.prototype.sayHi = function() { console.log(`${this.identify()} My team is called ${this.team} and I play as ${this.position}`); };

const lebron = new BasketballPlayer('Lebron James', 32, 'Basketball', 'Cleveland Cavaliers', 'Power forward');

lebron.sayHi();

Dziedziczenie prototypowe to najpopularniejszy wzorzec programowania obiektowego w JS. Programiści wykorzystują go praktycznie od samych początków języka.
Polega on na imitowaniu dziedziczenia klasowego za pomocą połączenia własności obiektów funkcjnych i operatora new.
Bazuje na wykorzystaniu efektów ubocznych, przez co może wydawać się skomplikowany dla początkujących.

Dziedziczenie prototypowe opiera się na wykorzystaniu obiektu F.prototype oraz konstrukcyjnego wywołania funkcji.

F.prototype to wbudowana właściwość każdej funkcji w JS. Gwoli ścisłości, mówimy o właściwości prototype hipotetycznej funkcji o nazwie F. Domyślnie F.prototype jest obiektem,
który zawiera wyłącznie jedną właściwość. Nazywa się ona constructor i wskazuje z powrotem na F. W naszym programie wykorzystujemy dwa takie obiekty: BasketballPlayer.prototype i Player.prototype.

Jeżeli zmienimy prototyp funkcji na nowy obiekt, musimy liczyć się z tym, że jego właściwość constructor przestanie wskazywać na F.
Aby tego uniknąć, modyfikujemy prototyp poprzez dodawanie/usuwanie właściwości – F.prototype.method = .... Jednak, często zależy nam na ustawieniu konkretnego prototypu dla hodowanych obiektów. Właśnie z tego powodu, przypisałem do BasketballPlayer.prototype pusty obiekt za pośrednictwem Object.create(). Jego [[Prototype]] wskazuje na Player.prototype. Dzięki temu, mogę odwoływać się do właściwości Player.prototype, z poziomu BasketballPlayer.prototype, za pomocą wskaźnika this.

Ten sam mechanizm wykorzystują wbudowane obiekty globale, które również posiadają właściwość prototype. Najpopularniejsze z nich to: Object, String, Array.
Podczas inicjalizacji zmiennej tablicowej, silnik automatycznie ustawia [[Prototype]] na Array.prototype. Właśnie dzięki temu mamy możliwość wykorzystywania wielu metod, m.in. Array.prototype.filter, Array.prototype.map, Array.prototype.reduce.

Do tworzenia nowych obiektów na bazie prototypu, stosujemy konstrukcyjne wywołanie funkcji, czyli poprzedzone operatorem new. Wiążą się z tym następujące efekty uboczne:

  • Wywołanie funkcji z operatorem new skutkuje utworzeniem obiektu.
  • Nowy obiekt będzie miał własność [[Prototype]] wskazującą na F.prototype.
  • Wiązanie this wewnątrz wywoływanej funkcji będzie wskazywało na nowo utworzony obiekt.
  • Jeżeli funkcja nie zwraca innego obiektu, dojdzie do automatycznego zwrócenia nowego obiektu.

Uwaga: nie należy mylić ze sobą F.prototype oraz [[Prototype]]. To dwie różne właściwości. Jedna jest charakterystyczna
wyłącznie dla funkcji oraz obiektów globalnych, podczas gdy [[Prototype]] to ukryta właściwość każdego obiektu w JS.

Delegacja zachowań – analiza wzorca

const Player = {
init(name, age, discipline) {
this.name = name;
this.age = age;
this.discipline = discipline;
}

const BasketballPlayer = Object.create(Player);

BasketballPlayer.setup = function(name, age, discipline, team, position) {
this.init(name, age, discipline);
this.team = team;
this.position = position;
}

Player.identify = function() { console.log(`Hello, I'm ${this.name}. I'm ${this.age} and I play ${this.discipline}`); };

BasketballPlayer.sayHi = function() { console.log(`${this.identify()} My team is called ${this.team} and I play as ${this.position}`); };

const lebron = Object.create(BasketballPlayer);

lebron.setup('Lebron James', 32, 'Cleveland Cavaliers', 'Power Forward');

lebron.sayHi();

W tym wzorcu korzystamy z dwóch typów obiektów: delegatów (Player, BasketballPlayer) i delegujących (lebron).
Warto zwrócić uwagę, że stan jest przechowany w obiekcie delegującym. Delegaci służą nam wyłącznie jako kontenery zachowań. Aby w pełni wykorzystywać zalety prototypowania, nie stosujemy cieniowania metod. Specjalnie rozgraniczyłem metody init i setup oraz identify i sayHi, tak, abym mógł odwołać się do każdej z nich w obiekcie delegującym, z użyciem wskaźnika this.

Więcej informacji o OLOO znajdziecie w drugim materiale uzupełniającym, który czeka na Was w dalszej części wpisu.

Materiały uzupełniające

  1. javascript.info – po raz kolejny odsyłam Was w ręce Ilyi Kantora. Tym razem wykorzystamy aż cztery treściwe wpisy o prototypach – Prototypal inheritance, F.prototype, Native prototypes oraz Methods for prototypes.
    Każdy z nich jest pełen grafik pozwalających na zwizualizowanie sobie omawianych zagadnień. Co najważniejsze, na końcu każdego wpisu czeka na Was kilka zadań. Łącznie będzie ich aż 10!
    Po takiej ilości solidnych materiałów i przećwiczonych przykładów, prototypy nie będą miały przed Wami tajemnic.
  2. YDKJS: this and object prototypes, Chapter V i Chapter VI – podstawy delegacji zachowań i dziedziczenia prototypowego poznaliście podczas analizy przykładów.
    Wytłumaczenie tajników tych wzorców pozostawiam Kyle’owi Simpsonowi. Będzie to świetna okazja do ugruntowania Waszej wiedzy z całego programowania obiektowego w JS.

Pytania kontrolne

Okej, na koniec mam dla Was listę pytań. Z ich pomocą możecie sprawdzić ile udało się Wam zapamiętać. Jeżeli uważnie przeczytaliście wpis, to nie powinno być problemów z udzieleniem poprawnych odpowiedzi. W razie wątpliwości, służę pomocą w komentarzach.

  1. Czym jest właściwość [[Prototype]] obiektów?
  2. Czym jest obiekt prototypowy?
  3. Czy można dziedziczyć metody i właściwości za pomocą łańcucha prototype?
  4. Czy istnieje możliwość bezpośredniej interakcji z właściwością [[Prototype]]code>?
  5. Jakie są sposoby na modyfikację [[Prototype]]?
  6. Czy prototyp może być wartością prymitywną?
  7. Jaka jest maksymalna ilość prototypów pojedynczego obiektu?
  8. Czy prototyp ma wpływ na wskaźnik this?
  9. Na co wskazuje właściwość F.prototype?
  10. Jaka jest domyślna wartość F.prototype?
  11. Czy silnik JS zapewnia utrzymanie poprawnej wartości dla właściwości constructor?
  12. Jak utrzymać poprawną wartość constructor, jednocześnie modyfikując F.prototype?
  13. Jaka jest różnica pomiędzy [[Prototype]], a F.prototype?
  14. Jakie wartości przyjmuje F.prototype?
  15. Na czym polega wzorzec delegacji zachowań?
  16. Na czym polega wzorzec dziedzieczenia prototypowego?

Zachęcam do przekucia powyższych pytań w karty Anki. W przypadku konieczności zapamiętania takiej ilości zasad i niuansów, metoda Anki jest wyjątkowo skuteczna.

Podsumowanie

Możecie śmiało odhaczyć programowanie obiektowe na liście ‚do opanowania przed nauką Reacta’. Wskaźnik this i prototypy mamy w małym paluszku.

Dobrze się składa, bo wielkimi krokami zbliża się koniec 2017 roku. W kolejnym, ostatnim w tym roku, wpisie pojawią się zagadnienia z programowania funkcyjnego. Ze względu na szeroki zakres materiału, chciałem przeznaczyć na ten temat aż trzy artykuły. Czasu wystarczy tylko na jeden. Obiecuję, że nic istotnego nie zostanie pominięte.

Od samego początku 2018 roku zaczynamy zabawę z Reactem. Nie mogę się doczekać. A Wy? Czujecie się na siłach? Czy seria ‚Powtórka przed ReactJS’ była dla Was pomocna? Dawajcie znać w komentarzach, piszcie do mnie na fejsbuku albo ćwierkajcie na Twitterze.

Idą święta. Nie bądź sknera, podaruj programistycznym znajomym prototypową dobroć. Wystarczy podzielić się tym wpisem na social media.

Do zobaczenia pod koniec grudnia. Wesołych świąt!

Zdjęcie tytułowe autorstwa: Jo Szczepanska

ZawodProgramista-wide

Zawód: Programista – recenzja książki

Książkę Zawód: Programista: Wszystko, czego potrzebuje świadomy developer autorstwa Macieja Aniserowicza nabyłem w przedsprzedaży. Wystarczy zerknąć na świetne wyniki sprzedażowe, aby zdać sobie sprawę, jak wielu programistów darzy zaufaniem autora bloga devstyle.pl. Byłem ciekaw, jak Zawód: Programista wypadnie na tle Dev Career Guide Johna Sonmeza. Autorzy postawili sobie dokładnie ten sam cel: stworzyć kompletny przewodnik programisty po branży IT. Czy Maciej przedstawia unikalne treści, których na próżno szukać w dużo obszerniejszej książce autorstwa popularnego na całym świecie Simple Programmera? Czy udało się osiągnąć cel postawiony w podtytule książki i rozszerzyć moją developerską świadomość? Zobaczmy.

(więcej…)

Mężczyzna wskazujący na pokaz fajerwerków.

Wskaźnik this – Powtórka przed ReactJS #9

Wskaźnik this stanowi fundament programowania zorientowanego obiektowo. Niestety, w przypadku JavaScript, jest jedną z najbardziej zagmatwanych części języka. Zarówno początkujący, jak i weterani innych języków programowania, będą mieli wiele okazji do złapania się za głowę. W przeciwieństwie do Javy i C#, wartość this nie zawsze wiąże się z obiektem/funkcją zawierającą to słowo kluczowe.
(więcej…)
Droga za ogrodzeniem.

Domknięcia – Powtórka przed ReactJS #8

Zacznijmy od spraw natury czysto organizacyjnej. Od dnia dzisiejszego, wpisy z serii Powtórka przed ReactJS, będą miały odmienną formę niż dotychczas.

Do tej pory skupiałem się na kompleksowym omawianiu wybranych zagadnień. Takie podejście miało liczne zalety w zakresie opracowania najistotniejszych fragmentów specyfikacji ES6. Mamy końcówkę 2017 roku, a mimo to nadal trudno wskazać wyczerpujące i jednocześnie zwięzłe materiały do nauki ‚nowości’, które stały się częścią standardu przeszło dwa lata temu.

Jeżeli chodzi o tematykę zaplanowaną na drugą część serii, sprawa wygląda zupełnie inaczej. (więcej…)

Azjatka otoczona przez kolorowe bąbelki mydlane.

Zakresy – Powtórka przed ReactJS #7

Bez zrozumienia zakresów nie obejdzie się podczas pisania nawet najprostszych programów. Tak pozornie banalne zagadnienie zawiera wiele niuansów, które wprowadzają w dezorientację wielu początkujących. Większość z owych niuansów odchodzi w niepamięć po zrezygnowaniu z wykorzystywania var na rzecz let i const. Czy jest to wystarczający powód, aby pominąć temat? W żadnym wypadku. Dogłębne opanowanie mechaniki zakresów jest bardzo często sprawdzane podczas rozmów kwalifikacyjnych. Wystarczy zrozumieć kilka prostych zasad, żeby znacznie zwiększyć szansę na zdobycie wymarzonej pracy. (więcej…)

Rozmywa sylwetka chłopaka otoczonego regałami książek.

Anki, czyli jak zapamiętuję WSZYSTKO czego się uczę

Do powszechnej świadomości weszło przekonanie, że opanowanie umiejętności do mistrzostwa wymaga poświęcania magicznej liczby 10 tysięcy godzin. Prosta matematyka, wystarczy zainwestować „jedynie” trzy godziny dziennie przez okres 9 lat i będziemy zbijali piąteczki z Maciejem Aniserowiczem. Jak przekonuje Peter C. Brown w swojej książce Peak: Secrets from the New Science of Expertise sprawa wcale nie jest taka prosta. Osiągnięcie biegłości to nie tylko kwestia poświęcenia odpowiedniej ilości czasu. O tym czy i kiedy uda nam się dotrzeć na linię mety, decyduje przede wszystkim przemyślana praktyka. To właśnie ona pozwala na utrwalenie niezbędnej wiedzy. (więcej…)

Mężczyzna w bordowej koszuli pakujący pudełko w pracowni.

Moduły ES6 – Powtórka przed ReactJS #6

Brak wbudowanego systemu modułów w JavaScript stanowił problem od dawien dawna. Różne wzorce projektowe i techniki stanowiły zastępcze rozwiązanie problemu. Najpopularniejsze z nich to moduły opakowane w biblioteki, loader RequireJS, wstrzykiwanie zależności w AngularJS oraz powszechnie uznawany król – CommonJS. To właśnie w oparciu o CommonJS zaimplementowano natywną funkcjonalność w ramach specyfikacji ES6. (więcej…)

Czworo przyjaciół zbijających żółwika nad stołem.

Obietnice – Powtórka przed ReactJS #5

Obiecuję, że po przeczytaniu tego wpisu, Wasz kod asynchroniczny stanie się bardziej czytelny. Skąd taka pewność siebie? A no, społeczność JavaScript od dwóch lat zachęca do jak najczęstszego składnia obietnic. Spokojnie, to nadal powtórka przed ReactJS, a nie zapowiedź mojego startu w plebistycie na najlepszego blog front-endowy. Na to przyjdzie czas wiosną 2018 roku #DSP ;). (więcej…)

Trzy lukrowane pączki leżące na blacie pełnym kolorowej posypki.

Spread, rest i default – Powtórka przed ReactJS #4

Funkcje wykorzystujące tablice to chleb powszedni każdego programisty JavaScript. Mając to na uwadze, komitet TC39 zatroszczył się o wprowadzenie kilku użytecznych usprawnień, które rozszerzają nasze możliwości. Oprócz nowinek, zastąpimy stare rozwiązania bardziej eleganckim kodem. Panie i Panowie, oto bohaterowie dzisiejszego wpisu: spread, rest i default. (więcej…)