Nowy Standard JavaScript
10 godz. 43 min · JavaScript · Full-stack i Programowanie
Piotr PalarzWeb DeveloperNa początku dowiesz się jakie nowości pojawiły się w języku, jeśli chodzi o tworzenie zmiennych i stałych. Poznasz dwa nowe słowa let i const, a także dokładnie omówimy ich różnice, względem znanego nam do tej pory słowa var. Następnie poruszymy temat obiektów. Zobaczysz jak nowy zapis pozwoli znaczenie ułatwić nam pracę i sprawić, by kod był bardziej czytelny. W kolejnym rozdziale porozmawiamy o zmianach w funkcjach. Poznasz tzw. arrow functions wraz z poradami, kiedy z nich korzystać, a także z konsekwencjami ich użycia. Zobaczysz również, jak korzystać z domyślnych parametrów. Następną nowością będą operatory rest i spread, które znacząco uproszczą pisanie kodu dla funkcji i tablic. Chwilę później rzucimy okiem na bardzo ciekawy temat, mianowicie na tzw. destructuring. To nowa funkcja języka, która pozwala w łatwy sposób wyciągnąć odpowiednie dane z tablic i obiektów, nawet jeżeli te posiadają kilkupoziomową, zagnieżdżoną strukturę. Zmian doczekały się również ciągi znaków. Poznasz nowy zapis, tzw. template string, a także możliwość wykorzystania funkcji tagujących.
ES6 wprowadza do języka JavaScript zapis klas. I choć na początku wydaje się, że to duży krok w stronę klasycznych obiektowych języków programowania, to jak się przekonasz, jest to w dużej mierze tzw. syntactic sugar, a więc zupełnie nowy, prostszy zapis, a prawie identyczne jak wcześniej działanie, oparte na dziedziczeniu prototypowym. W kursie poruszymy również temat Symboli oraz tego jak z nimi pracować, a chwilę później poznasz iteratory. To konstrukcje ułatwiające iterację, które znacząco upraszczają pracę z kolekcjami danych. Wraz z iteratorami poznasz również generatory, które ułatwiają z kolei tworzenie tych iteratorów. Istotną nowością w ES6 są również natywne Promise. To sposób na rozwiązanie problemu asynchroniczności, który znamy od bardzo dawna w postaci różnych bibliotek. Od teraz jednak Promisy znajdują się bezpośrednio w języku. Nowymi konstrukcjami, które pozwalają pracować z kolekcjami danych, są Map i Set. Dowiesz się jak z nich korzystać, a także do czego są przydatne. W jednym z rozdziałów rzucimy też okiem na tzw. Proxy API. To mechanizm języka, który pozwala na dość niskopoziomowy dostęp do różnych operacji. I choć być może nie jest to coś, z czego będziesz korzystał nad wyraz często, to warto wiedzieć, jakie są nowe możliwości tego API.
Jedną z najlepszych nowości, która zawitała do języka JavaScript wraz z ES6 są moduły. To możliwość dzielenia kodu na wiele plików, z których można pewne wartości wyeksportować, a następnie zaimportować je w innych modułach. Tutaj dowiesz się wszystkiego, co z modułami związane. Zobaczysz wiele sposobów na eksport i import, a także jak pracować z modułami w przeglądarkach internetowych. Kurs skupia się na omówieniu wszystkich najważniejszych nowości w ES6, dzieląc je na rozdziały. Jeden z nich natomiast, poświęcony został omówieniu mniejszych zmian, które znalazły się w specyfikacji. Poznasz w nim np. nowe metody tablic czy ulepszoną współpracę z Unicode.
Specyfikacja EcmaScript 2015 wprowadziła naprawdę bardzo wiele zmian, ale jej twórcy założyli, że od tego czasu każda kolejna wersja specyfikacji będzie pojawiać się co roku. Oznacza to przede wszystkim, że nie będziemy na raz bombardowani aż tak wieloma zmianami, jak w 2015 roku. W tym kursie nie zabrakło zatem omówienia nowości ze specyfikacji ES2016 oraz 2017, gdzie poznasz np. nowe metody dla stringów czy funkcje asynchroniczne.
Kiedy będziesz już uzbrojony w solidną wiedzę z zakresu nowości w ES6, dowiesz się jak w praktyce pracuje się dzisiaj z tym standardem. W jednym z rozdziałów omówimy nowoczesny workflow z użyciem npm i wykorzystamy popularne narzędzie webpack, do pracy z modułami, a także do transpilowania kodu ES6 do wersji ES5. Dzięki temu nowoczesny kod, który napiszemy, będzie mógł być uruchamiany również w starszych przeglądarkach, które nie wspierają najnowszego standardu. Dowiesz się na co zwrócić uwagę, by wszystko działało bez zarzutu.
Zwieńczeniem tego kursu będzie praktyczny projekt, w którym od podstaw wykonamy swoją własną bibliotekę do pracy z Obiektowym Modelem Dokumentu. Będzie ona w działaniu nieco podobna do znanej chyba wszystkim biblioteki jQuery. Na tym przykładzie postaramy się wykorzystać jak najwięcej wiedzy z zakresu ES6 zdobytej wcześniej. Stworzymy metody do pracy z drzewem dokumentu, a więc do wyszukiwania elementów, do tworzenia nowych, do przypisywania im klas, atrybutów czy styli CSS. Nie zabraknie również modułu odpowiedzialnego za współpracę z Ajax. Cały kod utworzymy oczywiście w sposób modułowy, aby bibliotekę można było łatwo rozwijać w przyszłości. Na koniec projekt ten przetranspilujemy do kodu ES5 z użyciem Babel i przetestujemy w starszej przeglądarce Internet Explorer 11, aby upewnić się, że nasza biblioteka działa poprawnie.
Kurs ten jest dla wszystkich osób, które znają już język JavaScript i czują się w pracy z nim swobodnie. Jeśli zatem chciałbyś pracować z nowoczesnym kodem JavaScript, to ten kurs jest zdecydowanie dla Ciebie. A może masz zamiar poznać framework Angular lub bibliotekę React? Tam również wykorzystywany jest najnowszy zapis ES6, więc wiedza ta będzie naprawdę pomocna. Z solidną wiedzą z zakresu EcmaScript 6, bez trudu pozostaniesz na bieżąco z każdą kolejną edycją tej specyfikacji.
Kolejnym tematem, którym zajmiemy się jeżeli chodzi o klasy jest dziedziczenie i
pokażę ci jak to wyglądało w EcmaScript5 najpierw. Mówimy
tutaj oczywiście o dziedziczeniu prototypowym i w przypadku klas, chociaż zapis jest inny,
wciąż jak widziałeś wersji poprzedniej, operujemy na prototypach. Tak więc
zacznijmy sobie od takiego prostego przykładu. Mamy to co w lekcji poprzedniej, czyli ES5
i tutaj utworzyliśmy sobie można powiedzieć klasę, która ma na prototypie
metodę sayHello i powiedzmy, że teraz tej klasy person chciałbym utworzyć
sobie jeszcze nową klasę, czyli utworzyć osobny konstruktor, który będzie się nazywał employee
jak pracownik i chciałbym, żeby on pewne rzeczy dziedziczył z Person. Wciąż
pozostajemy jakby w takich prostych przykładach. Niemniej jednak zapewniam cię, że jeżeli poznasz
to wszystko i to zrozumiesz, to na wielu innych przykładach będziesz widział kiedy możesz skorzystać
z dziedziczenia, kiedy to może być przydatne i dziedziczenie na tego typu,
zapewniam cię jest szczególnie przydatne na przykład kiedy korzystamy z JavaScript'u
w Node.js. To z wielu różnych typów, z wielu różnych obiektów można korzystać. Natomiast
tutaj posłużymy się prostym przykładem. Utwórzmy sobie zatem taką klasę
jak employee i powiedzmy, że chcielibyśmy,
aby pracownik też miał pierwsze imię, nazwisko i position, czyli
jakby jego pozycję w firmie, jego zawód. I teraz, w
jaki sposób moglibyśmy tutaj zrobić dziedziczenie? Może najpierw sobie utworzymy nowego
pracownika, czyli employee jeden, z małej litery
sobie może to napiszemy i będę chciał wywołać ten konstruktor i
przekazać tutaj Jan Kowalski,
stanowisko to będzie programista, okej.
I w tym przypadku nie będziemy mieć żadnego błędu, ale też nic ciekawego się nie wydarzy. Tak,
więc chciałbym żeby Jan Kowalski sobie dziedziczył z
tej klasy person, czyli ta klasa pracownik, żeby dziedziczył z person i oczywiście dziedziczenie
polega na tym, że będzie miała przypisane do nowo utworzonego obiektów firstName i lastName.
Dodatkowo dopiszemy sobie position, ale także to, że będziemy mogli skorzystać
z metody sayHello, więc tutaj musimy sobie zrobić coś takiego
i też mam nadzieję, że ten zapis już znasz, tak to wyglądało w EcmaScript
5. Tutaj pod this, jeżeli tworzymy nowy obiekt, to będziemy mieli nowo
utworzone obiekt, na którym jeszcze nic nie ma i chciałbym do niego dodać firstName i lastName. Nie
będę tego powtarzał, w ten sposób. Chociaż mam je tutaj przekazane, bo
wtedy to nie byłoby żadne dziedziczenie. Tak więc, możemy się odwołać do Person. Wiemy,
że jest to funkcja, a funkcje mają metody call i ta metoda pozwala wywołać
sobie taką funkcję, przekazując co ma być pod this czyli cokolwiek tutaj wpisze
to będzie dostępne pod this. Dlatego wpiszę this, czyli ten nowoutworzony
obiekt i dzięki temu ta funkcja się wywoła, gdzie wewnątrz this będzie
kierowało na ten nowy obiekt i będziemy do niej mogli przypisać to, co tutaj przekażemy, a
te dwa parametry można przekazać jako kolejne, czyli Jan Kowalski, mam je tutaj. One
się nazywają tak samo, ale to nie ma żadnego znaczenia i na
tym etapie powinniśmy mieć obiekt, możemy to sprawdzić, który będzie miał wewnątrz Jan
Kowalski. Zobaczmy tutaj employee1. No
i widzimy Jan Kowalski, czyli już sobie zrobiliśmy takie dziedziczenie, przynajmniej
jakby z tego konstruktora, że zostało to przypisane do tego obiektu. Teraz chciałbym
tutaj dodać position, tę którą nam ktoś przekazał i sprawdźmy
to sobie, jak to będzie teraz wyglądać. Widzimy, mamy position programista,
czyli te dwie właściwości zostały nam ustawione tutaj przez konstruktor
tej klasy nadrzędnej, a position dodaliśmy sobie sami. Teraz jak możemy
zrobić, żeby metoda sayHello również była dostępna na tutaj employee. Jeżeli
byśmy sobie zrobili console.log employee1 sayHello, to
otrzymamy błąd. Jak widzisz, z tego powodu, że na prototypie nigdzie
nie została znaleziona taka metoda, więc ustawienie prototypów wygląda
w ten sposób, że napiszemy sobie employee prototype. Tutaj
jest jakiś obiekt, ale możemy go nadpisać czym tylko chcemy, więc
korzystamy z funkcji czy z metody create, która jest dostępna jako
statyczna metoda na takim konstruktorze object i ona
tutaj pozwoli nam podać czym ma być prototyp nowo utworzonego obiektu,
czyli create zwraca nam nowy obiekt, który mogę tutaj przypisać, ale prototypem
tego nowo utworzonego obiektu chciałbym, żeby było person prototype, czyli person prototype,
to też jest jakiś obiekt i teraz zostanie zwrócony nowy
obiekt, którego prototypem jest person prototype i w ten sposób uzyskujemy
dziedziczenie, ale jeszcze jest jedna ważna rzecz, którą należy zrobić. Nadpisaliśmy cały
prototypyp employee, a w nim znajdowało się coś takiego, jak właściwość constructor. Dlatego
teraz muszę ją dodać i ona powinna kierować na
właśnie employee. Dzięki temu każdy obiekt, taki jak utworzony
tutaj. Po kropce constructor, będzie kierował na klasę, w której został utworzony.
W ten sposób zrobiliśmy dziedziczenie i zauważ, że funkcja sayHello zwraca Jan
Kowalski. Natomiast, ja bym chciał jeszcze sobie zrobić jedną rzecz, czyli nadpisać
funkcję sayHello, a więc employee prototype sayHello.
Możemy to zrobić jak najbardziej i teraz będzie wywoływana
ta funkcja, którą ja tutaj wpisze, kiedy skorzystamy z employee sayHello, bo
na jego prototypie zostanie znaleziona, więc nie szukamy dalej. Teraz kiedy jej nie było, to
szukaliśmy w prototypie nadrzędnym, czyli w tym przypadku person prototype, ale
chciałbym tutaj móc skorzystać z metody, która jest dostępna na
klasie nadrzędnej i do niej sobie coś dodać, to co wpiszę tutaj. Chciałbym
zatem, żeby to co zwraca ta metoda sayHello, czyli firstName i lastName, to
co widzimy w tym miejscu, żeby zostało zwrócone kiedy skorzystam już z własnej metody sayHello. Dlatego
utworze zmienną name i musimy się odwołać do tej klasy nadrzędnej, czyli Person,
następnie do prototype i do sayHello, tak musimy to
zrobić w EcmaScript 5. Zaraz zobaczysz jak to wygląda w ES6 i tak
naprawdę doszliśmy sobie w tym momencie to metody i chciałbym ją wywołać przekazując
jej this z tego obiektu, więc mogę to zrobić poprzez call this. Wtedy
to this spadnie tutaj i zostanie mi zwrócony Jan Kowalski w tym konkretnym przypadku i
teraz z mojej metody sayHello, gdybym to zwrócił dalej, no
to ona by działała dokładnie tak samo zauważ, ale chciałbym sobie tutaj coś dodać, więc
zrobimy coś takiego. Nazywam się i do
tego sobie dodamy name i następnie i pracuję
jako i do tego dodamy sobie this position i
na końcu jeszcze kropka. W razie czego sobie zapauzuj
to wideo, żebyś zobaczył dokładnie, co tutaj się dzieje, ale generalnie chcę wywołać metodę klasy
nadrzędnej, która mi zwróci Jan Kowalski, czyli jest to ta metoda i
kiedy już to mam to chcę wstawić sobie to w tym miejscu, a z mojej
metody sayHello zwrócić jeszcze coś takiego i teraz będzie to tak wyglądać, nazywam
się Jan Kowalski i pracuję jako programista. Tutaj jeszcze zabrakło spacji,
ale widzisz jak działa i teraz jeżeli w klasie nadrzędnej metoda sayHello by się zmieniła,
to nasza klasa również bierze to pod uwagę. Jak zatem widzisz, aż tyle
kodu musimy napisać, żeby zrobić sobie dziedziczenie prototypowe w EcmaScript
5, a teraz pokażę ci jak zrobić to w ES6 i będzie to wyglądać
naprawdę dużo, dużo ładniej. Wykomentujemy za tym wszystko
co tutaj mieliśmy do tej pory. Skopiuję sobie tylko ten
konstruktor i od nowa utworzymy tą klasę Person,
w środku pamiętaj, że zrobimy sobie metodę constructor. Ona
będzie przyjmować firstName, lastName i wewnątrz
to samo, co mieliśmy lekcji poprzedniej i to co mieliśmy tutaj wyżej. Następnie
dodamy sobie metodę sayHello, w ten sposób, okej
i w zasadzie nawet możemy ją skopiować z lekcji poprzedniej, mieliśmy ją tutaj. Będzie
troszeczkę szybciej, okej. No i teraz też będęsobie
tego employee tworzyć. Jak jesteśmy w ES6, to pamiętajmy,
że możemy korzystać na przykład z let, tylko że klasy employee musimy sobie teraz
utworzyć i teraz pokażę ci jak wygląda takie dziedziczenie. Domyślasz się pewnie, że też
napiszemy employee, tworząc taką klasę, ale teraz nie postawimy takich
nawiasów, tylko najpierw napiszemy extends, czyli
rozszerza i tutaj musimy podać jaką klasę, czyli person. W ten
sposób tworzymy klasę pochodną, czyli mówimy że employee ma rozszerzać Person i tutaj
również możemy sobie utworzyć swój konstruktor, który będzie przyjmował
tak jak zrobiliśmy to wyżej przypadku employee firstName, lastName i position. Okej,
w ten sposób. No i teraz pytanie brzmi kiedy skorzystamy z new employee
i przekażemy te trzy parametry, to jak powinniśmy zasymulować, to co
robiliśmy tutaj, czyli person call this firstName, lastName. To
zostało znakomicie uproszczone, wystarczy, że napiszemy super i to
sprawia, że konstruktor klasy nadrzędnej, czyli ta funkcja jest wywoływana
i this jest ustawiony na nowo utworzony tutaj obiekt. Natomiast
jeżeli chcemy przekazać jakieś parametry, które tutaj są potrzebne, to możemy je tutaj wpisać, czyli
wpiszemy sobie na przykład firstName i lastName, bo tam je chcemy przekazać. Taki
zapis i ta funkcja super będzie się znajdowała wyłącznie tutaj w tej funkcji, sprawia,
że mamy tutaj już obiekt this utworzony tutaj, do którego
zostały dodane te rzeczy, które są w klasie nadrzędnej i teraz dopiero mogę dodać
sobie to, co chcę mieć w tej klasie, czyli position, na przekazane mi tutaj position.
Zobaczmy jaki będzie efekt, nie mamy błędu,
więc odwołajmy się do employee1
i następnie tutaj do na przykład firstName albo wyświetlimy sobie
cały ten obiekt i zauważ, że wszystko działa poprawnie. Natomiast jedna ważna uwaga.
Jeżeli nie dziedziczysz z klasy nadrzędnej, tak jak tutaj poprzez extends,
musisz skorzystać z super. Nie możesz nie skorzystać z super, nawet gdyby
tego nie było, niczego, będziemy mieli błąd dlatego, że super musi zostać
wywołane i kolejna ważna rzecz. Nie możesz skorzystać z this zanim
nie skorzystasz super, czyli taki zapis również spowoduje błąd, a więc
super powinno być na początku chyba, że będziesz robił tu jakiś warunek. Tutaj mogą
być jakieś zmienne, jakiś kod, ale nie możesz skorzystać z this. Mam
nadzieję, że na tym etapie już widzisz jak to wygląda i co jest ciekawe, nie musimy ustawiać prototypów
w taki sposób jak robiłem to tutaj. Nie muszę dopisywać constructor i nie
muszę przede wszystkim korzystać z tego call, czyli to co tutaj zrobiliśmy do tej pory,
to jest dokładnie to samo co zapisałem wyżej. Oznacza to, że employee
będzie miał metodę sayHello, więc spróbujmy się do niego odwołać i zobacz
zwraca nam to Jan Kowalski. Natomiast tak jak wyżej, ja sobie nadpisałem w klasie
employee tą metodę, w tym miejscu, więc dokładnie to samo chciałbym zrobić teraz. Skopiujemy
sobie zatem tę funkcję i w tym miejscu sobie ją dodamy. Pamiętaj, ona jest
dodawana na prototypie. W zasadzie to w tej klasie, okej, w
ten sposób. Okej
i teraz pytanie czy musimy tutaj robić person prototype sayHello call this. Coś
takiego to znowu brzydko wygląda. Tak musieliśmy zrobić wcześniej. Okazuje się, że nie, że
tutaj możemy się odwołać to super i po kropce
zauważ, że już teraz tego nie wywołuje tak jak zrobiłem tutaj, ale super kropka,
czyli samo super będzie mi kierować w tym przypadku na klasę nadrzędną,
dokładnie to na jej prototyp, więc mogę napisać super i nazwa metody sayHello i
to sprawi, że cały ten zapis, który
widziałeś przed momentem jest niepotrzebny, bo to działa dokładnie tak samo, czyli w tym przypadku
super sayHello odwoła się do klasy nadrzędnej. Wywoła jej metody sayHello,
ustawiając this na ten obiekt, w którym jesteśmy jakby aktualnie
i to mi zwróci Jan Kowalski, bo tutaj takie wartości też mieliśmy
przekazane i to już mogę sobie tutaj puścić dalej i powinniśmy mieć poprawny wynik,
employee sayHello. Jak widzisz dokładnie tak się dzieje. Z tego
powodu możemy sobie to jeszcze zamienić na syntax EcmaScript 6, żeby to
trochę lepiej wyglądało i zamiast tego name może
od razu zróbmy sobie super sayHello. Zobaczysz o ile prostsza będzie ta metoda, więc
napiszmy sobie tutaj takie wyrażenia jak w template string'ach. Można z nich korzystać i
oczywiście tutaj. Zrobimy to
w znane ci już sposób i zauważ jak to fajnie wszystko się łączy jeżeli chodzi
o ES6. Wygląda to dużo lepiej, bo stworzyliśmy klasy Person. Ma
ona konstruktor i metody na prototypie. Następnie klasę employee, która
dziedziczy z klasy person, ma swój konstruktor. Wywołuje konstruktor rodzica
w taki sposób i na swoim prototypie dodaje sayHello, które może skorzystać
z sayHello klasy nadrzędnej i samo this i wszystko będzie automatycznie poprawnie
ustawione. Zobaczymy raz jeszcze czy efekt będzie taki sam i jak widzisz dokładnie
tak się stało. Na koniec powiem ci o jeszcze jednej ciekawostce, otóż jeżeli
byś nie utworzył w klasie pochodnej konstruktora, tak jak zrobiliśmy to tutaj, to
nie będzie błędu. Możesz go nie utworzyć, tylko pytanie co się stanie. Jak widzisz nie ma
żadnego błędu. Wtedy JavaScript utworzy za ciebie domyślny konstruktor, który wyglądałby
tak, że zbierałby tutaj operatorem rest wszystkie
argumenty, które zostały przekazane, a to oznacza, że przy użyciu new employee,
te trzy argumenty zostałyby zapisane w tablicy args i następnie
wywołałby super, czyli konstruktor klasy nadrzędnej, przekazując
mu wszystkie te parametry operatorem spread, czyli napisałby po prostu args. W
ten sposób by to zadziałało, czyli JavaScript za ciebie utworzy taki domyślny konstruktor,
a więc wszystkie rzeczy, które tutaj przekażesz automatycznie on przekaże
do konstruktora klasy nadrzędnej jako poszczególne parametry. Tak,
więc nie musisz stworzyć konstruktora. Jeżeli nie chcesz przepisywać do swojego obiektu jakiś
innych rzeczy. Pamiętaj jednak i o tym nie wspomniałem w poprzedniej, że jeżeli
chcesz tak jak na przykład tutaj to zrobiliśmy przypisać coś do nowo utworzonego obiektu, to
musisz to zrobić w klasie czy w zasadzie w metodzie constructor. W innych
metodach też jest to możliwe, ale nie jest to możliwe tak jak niektórych językach programowania, na
przykład w tym miejscu, gdzie można by było sobie napisać, że name to jest powiedzmy Piotr. To
nie jest poprawny syntax ES6, a więc właściwości do obiektu można
dodać jedynie poprzez jego metody. Pamiętaj, że tak wyglądałby domyślny constructor
gdybyś go nie podał, dlatego ja go tutaj po prostu zostawię. To
by było na tyle w tej lekcji. W kolejnej będziemy oczywiście kontynuować temat klas. Natomiast
mam nadzieję, że widzisz o ile lepszy jest to zapis i powiedziałem ci już też
wersji poprzedniej jak on działa inaczej czyli jakie są różnice pomiędzy klasą, a
funkcją, która działa jak klasa, ale jest jeszcze kilka innych różnic, o których powiemy
później. Niemniej jednak zdecydowana większość z nich jak widzisz, to jest tylko
syntactic sugar, więc mamy zdecydowanie lepszy zapis, ale w gruncie rzeczy działa
to podobnie i prototypy również podobnie są ustawione, tak więc to co zrobiliśmy tutaj
wyżej jest prawie analogiczne do tego co jest tutaj.