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.
Pozostajemy jeszcze w tematyce obiektów, jeżeli chodzi o ES6 i w
tej lekcji pokażę ci kilka statycznych metod, które zostały dodane do obiektu
właśnie o nazwie object. Pokażę ci co można z nimi zrobić i do czego mogą
być przydatne. Na początek pokażę ci metodę, która nazywa się setPrototypeOf
i może ona nie będzie jakoś często wykorzystywana, ale warto wiedzieć, że
istnieje. Mam nadzieję, że rozumiesz do tej pory jak działają prototypy i dziedziczenie
prototypowe w języku JavaScript, bo jest to niezwykle ważne, aby zrozumieć
to co pokaże za moment. No i tak, że aby korzystać z innych, bardziej zaawansowanych rzeczy
w ES6, które jeszcze w tym kursie się pojawią. Na początek ja sobie wkleję
taki kod, czyli mamy zwykłą funkcję person, która przyjmuje dwa parametry, firstName i lastName
i następnie zapisujemy je w nowo utworzonym obiekcie i tego person
prototype dodałem sobie metodę sayHello, która po prostu zwróci nam te dwie wartości
połączone na spacji, co oznacza tylko tyle, że mogę teraz utworzyć
dwie nowe zmienne. Na przykład person1 i to będzie new
Person i przekażę właśnie wartości pod te parametry. Powiedzmy, że to
będzie Jan Kowalski i utworze
sobie jeszcze drugą zmianą, którą nazwę person2 i będzie to Anna Nowak,
więc to mam nadzieję, że rozumiesz. Po prostu z tego konstruktora, który również
można byłoby nazwać klasą tworzę sobie dwie nowe instancje i
każda z nich ma dostęp do metody sayHello na prototypie. Dlatego
jeżeli teraz bym chciał sobie zrobić console.log person1
sayHello i zrobimy dokładnie to samo z person2
to powinniśmy zobaczyć w konsoli Jan Kowalski,
Anna Nowak. Oba mają dostęp do prototypu, który
jest tutaj i teraz to co jest ważne w dziedziczeniu prototypowym. Moglibyśmy w dowolnym
momencie zmienić coś na tym prototypie i wszystkie obiekty nawet już utworzone
z tego konstruktora widziałyby te zmiany, więc gdybym teraz przed użyciem
tego wszystkiego napisał Person prototype sayHello i zmienił
tą funkcję, to te obiekty mimo tego, że już są utworzone skorzystają z
tej nowej zmiennej funkcji. Natomiast nie da się zmienić prototypu wyłącznie
dla jednego obiektu, w jakiś prosty sposób, więc co
tutaj chciałbym zrobić. Chciałbym zrobić tak, aby tylko jeden z tych utworzonych obiektów
miał inny prototyp i to będzie można zrobić metodą object setPrototypeOf.
Wkleję sobie tutaj jeden obiekt, który będzie miał metodę
sayHello również. Jest to taki zwykły literał obiektu
nazwanego methods i on po prostu ma w sobie metodę sayHello, która działa prawie
tak samo jak ta oryginalna, ale jeszcze wszystko zamienia na wielkie litery i teraz
chciałbym, żeby person1 nie korzystał już z tego prototypu, ale aby jego
prototypem stał się cały ten obiekt, który ma w sobie taką metodę. Można to zrobić
pisząc właśnie object setPrototypeOf i jako
pierwszy parametr podajemy już instancje takiego obiektu utworzoną, czyli na przykład person1, a
jako drugi to co ma stać się jego prototypem i to będzie wyłącznie dla
tej jednej instancji, więc napiszmy sobie methods i teraz sayHello, wywołajmy na
obydwu z nich. Okazuje się, że Jan Kowalski tutaj jest napisane wielkimi literami, czyli
po prostu skorzystał zupełnie innego prototypu i choć ta metoda może
nie jest w takiej codziennej pracy szczególnie ważna i przydatna, to została dodana
i warto o niej wiedzieć, gdybyś gdzieś w swoim kodzie potrzebował tymczasowo
zmienić prototyp jakiegoś obiektu na inny, aby pożyczyć od niego jakieś
metody czy po prostu z innych metod skorzystać. Kolejną
metodą, którą chciałem ci pokazać jest bardzo już tym razem przydatna metoda object
assign i jeśli kiedykolwiek korzystałeś w jQuery, w takiej bibliotece z dolar
extends, to będziesz wiedział czym jest object assign. Ja natomiast
będę chciał ci pokazać to na takim pół praktycznym przykładzie można powiedzieć,
więc stworzymy sobie taką funkcję, którą nazwę slider. Ja
ją tutaj wrzucę, jeszcze zakończę w ten sposób, czyli
powiedzmy, że tworzylibyśmy jakiś slider obrazów na stronę i chcielibyśmy dać możliwość
jego konfiguracji, więc mielibyśmy jakieś domyślne wartości tutaj w obiekcie
defaults i dodatkowo przy wywoływaniu takiego slider'a można by
było przekazać tutaj literał obiektu, który wpadnie pod config i jemu
przekazać jakieś opcje, które nas interesują. Te, które tutaj wpiszemy chciałbym żeby napisały
te, które są w tym miejscu, więc ja sobie tam jakieś opcje teraz wpiszę. Powiedzmy,
że tak by to mogło wyglądać, czyli chciałbym zmienić easing na trochę inny i czas
pauzowania, powiedzmy takiego slider'a też na inny. Czyli chciałbym generalnie zrobić
tak, aby w tej funkcji slider'a móc sobie zmiksować to co, jest
tutaj, z tym co jest tutaj. Jeżeli nie podałem tutaj speed, to chciałbym, żeby zostało domyślne.
Bardzo łatwo będzie to można zrobić. Utworzę sobie zmienną o nazwie options. Chociaż
w tym przypadku w zasadzie mogłaby to być nawet stała i skorzystamy
z object assign, czyli z tej metody, o której mówiłem i tutaj przekazujemy
dowolną liczbę tak naprawdę parametrów czy argumentów. Przekazujemy
generalnie obiekty, które będą łączone od prawa do lewa. Jeżeli bym tutaj napisał defaults,
a tutaj config to zadziała to w ten sposób, że to co jest z tym configu
zostanie wstawione do defaults i nadpiszę te wartości, które są w tym miejscu, ale
wtedy zostałby zmodyfikowany ten obiekt defaults, a tego bym nie chciał, dlatego
sobie tutaj wstawię nowy pusty obiekt i znowu od prawej do lewej to będzie działać, czyli
config, to co jest w tym miejscu. Zostanie wstawiony do defaults i nadpisze to co z tym
miejscu, ale na przykład nie napisze speed, a potem wszystkie te rzeczy zostaną wstawione
do tego obiektu i on zostanie zwrócony pod options. Dzięki temu jeśli
teraz bym sobie wyświetlił options, to zobaczymy, że mamy speed 500,
ale pauza jest o 1000 i easing również jest zmieniony na taki jak podałam. Dzięki
temu, jak widzisz, możesz sobie stworzyć jakieś rozwiązanie, które pozwoli
ci miksować wiele obiektów. Ważne jest jednak, aby wiedzieć, że te
wartości, które są prymitywne tak jak string czy number, one są kopiowane. Natomiast
każda inna wartość, która jest obiektem, nie jest skopiowana tylko nie skopiowana
jej referencja, czyli tak jak ma to miejsce zawsze w języku JavaScript. Zatem
co to oznacza, jeżeli bym w tym config'u, który mogę podać, podał sobie jakąś funkcję.
Wiesz, że mogę napisać to w ten sposób albo już skrótowo metodą o której
się dowiedziałeś lekcji poprzedniej, stworzymy sobie jakąś funkcję. Ona się znajdzie
w tym config'u zostanie wrzucony jakby do tego co jest w defaults i następnie
do tego co jest tutaj, to w options ona również się znajdzie, ale to nie
będzie jej kopia tylko to będzie dokładnie ta sama funkcja. Można
to sprawdzić wpisując options fn. Czy to jest dokładnie to samo, co
przekazany config fn. Jeżeli nam zwróci true w konsoli,
a tak się dzieje, to wtedy mamy potwierdzenie tego co mówię, czyli pamiętaj, że wartości
prymitywne za pomocą object assign są kopiowane, czyli gdybym teraz
po wykonaniu tego zmienił coś w config, na przykład pause. No to nie
zmieni się już w options. Natomiast jeżeli bym zmienił coś w samej tej funkcji, czy
w jakim obiekcie, który by tutaj był, jakąś jego właściwość. To ona będzie zmieniona
również tutaj, bo ten obiekt w żaden sposób nie jest kopiowane, ale tylko jest
skopiowana jego referencja i na koniec pokażę ci jeszcze jedną metodę, która
od czasu do czasu może być przydatna i jest to object is. Ona
pozwala nam porównywać dwie wartości, więc jeżeli bym napisał tutaj na przykład 1
i 1. Podajemy je jako osobne argumenty, to on nam zwraca true lub false
czy te wartości są równe i generalnie działa to praktycznie dokładnie tak samo jak
byśmy porównywali tym potrójnym znakiem równości, czyli string equality operator.
Mam nadzieję, że wiesz jak on działa, więc praktycznie w każdej
sytuacji wygląda to identycznie. Ja sobie może wkleję taki kod, który nam to pozwoli
porównać. Zobacz. Najpierw robię console.log, żebyśmy wiedzieli na
czym pracujemy i później na przykład będę chciał porównać dwa puste obiekty. Czy one są równe? Widzimy,
że nie. No i dokładnie tak samo by było, gdybyśmy chcieli je porównać w ten sposób,
bo choć wyglądają tak samo, są to dwa różne obiekty w języku JavaScript. No i object
is nam to zwrócił. Tutaj na przykład sprawdzamy czy 22 jest równe 22. Mamy
wartość true, czyli na razie nie ma tutaj zaskoczenia. Natomiast jest pewien
przypadek, kiedy operator potrójnego porównania zwraca nam dziwne wartości.
Być może takie, z którymi się nie zgadzamy czy są dla nas niespodzianką.
Jeżeli mamy taką specjalną wartość jak NaN, czyli Not a Number. Gdybyśmy
chcieli sprawdzić czy NaN jest równe NaN, okaże się, że to jest false. Dlatego
musimy korzystać z metody isNaN i tutaj przekazać
jakąś na przykład zmienną, która przechowuje taką wartość, a ona może być z jakiejś kalkulacji gdzie
chcieliśmy na przykład podzielić 20 przez słowo cześć. No
więc taki NaN możemy mieć i tutaj to już działa poprawnie i drugą taką sytuacją
są wartości, które czasami przy różnych kalkulacjach mogą się pojawić. Takie jak plus zero. Czy
to jest równe minus zero? Okazuje się, że dla tego operatora
tak, a tak naprawdę są to różne wartości. Dlatego teraz jeszcze wkleję tutaj
to o czym wspomniałem. Zobaczmy
jak się tutaj zachowa Object is i podobnie z
wartością NaN. Wkleimy to sobie tutaj. Tutaj powinno być Object
is. Podamy mu tutaj minus zero oraz wartość
plus zero i i również sobie to skopiujemy,
żeby widać to było tutaj i podobnie
z NaN i zobacz co się stanie teraz. Okazuje się, że według operatora
czy według tej metody is na object minus zero i plus zero, to są
różne wartości, a na przykład NaN i NaN są to wartości takie same. Czyli zapamiętaj
tylko tyle, że o ten, ta metoda Object is
działa dokładnie tak samo jak porównywanie za pomocą takiego operatora. Natomiast
w dwóch przypadkach czyli minus zero i plus zero oraz NaN działa inaczej zwracając
wydawałoby się tym razem już poprawne rezultaty. Jeżeli zatem gdzieś w swoim
kodzie będziesz potrzebował porównać jakieś wartości. Oczywiście nie będziesz jej wpisywał w taki
sposób dosłowny, tylko one będą pod jakąś zmienną i z góry nie wiesz co tam
będzie, to dobrym pomysłem może być korzystanie właśnie z object is i wtedy
masz stuprocentową pewność, że jeżeli one są identyczne, to wtedy zostanie
zwrócone true.