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.
Tą lekcją kończymy poznawanie symboli, chociaż jeszcze z jednego specyficznego symbolu będziemy w tym
kursie korzystać, ale o tym później i pokażę ci teraz symbole wbudowane. Być
może w lekcjach poprzednich, nie do końca byłeś pewien, kiedy te symbole ci się przydadzą. Teraz
pokażę ci symbole wbudowane, które są bardzo przydatne, chociaż
to znowu nie oznacza, że w takiej normalnej codziennej pracy z każdego z nich będziesz korzystał. Zapewniam
cię, że nie, ale nie wyobrażam sobie żebyś nie wiedział przynajmniej, że takie symbole
istnieją i jak one działają. A więc możemy tutaj przejść do kodu i zauważ,
że w komentarzu od razu wypisałem wszystkie, tak zwane well-known symbols, czyli
symbole wbudowane. Mamy je dostępne na bezpośrednio jakby
na tej funkcji symbol, czyli my wcześniej korzystaliśmy z symbol, wywołując ją lub na przykład
mieliśmy jakieś metody typu keyFor, a okazuje się, że tutaj
mamy również pewne właściwości, które przechowują już gotowe symbole. Znowu
nie wiemy czym jest symbol, bo nawet jeżeli swój własny utworzymy, nie wiemy jaką on przechowuje
wartość. Ważne jest to, że ta wartość jest zawsze unikalna i dla nas od razu ES6
daje nam, oferuje nam pewne wbudowane symbole. I teraz
przejdziemy sobie przez kilka z nich, ale nie będziemy dokładnie tłumaczyć wszystkich. Powiem
ci tylko jak one działają. Zaczniemy od symbolu hasInstance. Utworzyłem
sobie klasy person, dokładnie w taki sposób, jak już mieliśmy i klasę
employee, która z niej dziedziczy. Możesz się temu kodowi przyjrzeć, natomiast
już to widziałeś tym kursie. Pamiętasz, że zasymulowaliśmy sobie tworzenie
klasy abstrakcyjnej, czyli takiej, z której nie można bezpośrednio użyć. Nie można z niej utworzyć
nowej instancji. Jest to przez ten oto zapis, więc nie możemy napisać new
Person. Nie będę ci już tego pokazywał, bo wiemy, że tak jest. Natomiast jeżeli
sobie utworzymy klasę pochodną, czyli employee, z klasy Person,
to pytanie czy employee jest instancją klasy person czy
nie. Sprawdźmy to sobie w przeglądarce piszący employee1
instanceof Employee najpierw. Okazuje
się, że tak, no bo została ona utworzona z new Employee, ale że employee dziedziczy
z Person, to zobaczmy czy employee jest też instancją klasy Person. Okazuje
się, że tak i pytanie czy moglibyśmy to zmienić. W EcmaScript 5 nie
mieliśmy dostępu, do niskopoziomowych rzeczy, które wykonywał interpreter
języka JavaScript i właśnie to w EcmaScript zostało w wersji 6 dodane. To
nie znaczy, że musisz z tego korzystać, ale to znaczy, że wielu deweloperów przez lata
czekało na takie możliwości. Stąd one teraz w postaci między innymi
symboli się pojawiły, ale również w postaci Proxy API, o którym jeszcze w tym
kursie będziemy mówić, więc symbol hasInstance pozwala
nam zdefiniować, co się stanie, kiedy ktoś użyje i może zróbmy
sobie to tutaj, operatora instanceof, czyli employee1,
instanceof Person. Do tej pory nie mieliśmy wpływu
na to, co tutaj się wydarzy. Okazuje się, że teraz za pomocą symbolu możemy przypisać funkcję,
która się wywoła kiedy ktoś spróbuje cokolwiek instanceof Person
wywołać. Wtedy będziemy w tej funkcji mieli do tego cokolwiek dostęp. Musimy
sobie to dodać na klasie Person, jako metodę. Pokazywałem ci już że
możemy wyliczone metody tutaj dodawać, czyli tak zwane computed properties i odwołamy
się właśnie do Symbol i następnie do hasInstance. W ten
sposób dodamy sobie pod Symbol hasInstance pewną metodę i język
JavaScript czy interpreter JavaScript'u w momencie, kiedy ktoś wywoła instanceof. Sprawdzi
czy na klasie Person, czyli na prawym operandzie, tutaj tego operatora, czy istnieje
dodana, poprzez symbol hasInstance metoda. Jeżeli tak, to
przekaże nam tutaj pod obj, to co jest po tej stronie i
zależności czy zwrócimy true lub false, to instanceof
zwróci true lub false. Więc w tym przypadku, skoro jest to klasa abstrakcyjna, z której nie
można tworzyć nowych żadnych instancji, to jeżeli jakaś instancja
z niej dziedziczy, to powiedzmy, że też chciałbym zwracać false, że employee nie jest
instancją tej klasy, wtedy bardziej działałoby to jak tak zwany interfejs. Niemniej
jednak, tutaj możemy sobie zwrócić za każdym razem false. Mógłbym
tutaj coś sprawdzać, bo po to mam to obj i będę miał pod
tym obj dostęp, dokładnie do tego obiektu, więc wszystko mogę na nim zrobić, ale
w tym przypadku chcę po prostu zwrócić false. Sprawdźmy, okej i mamy
true, czyli coś nam nie działa, mógłbyś się zastanawiać dlaczego. Okazuje się, że jeżeli
dodaliśmy to w ten sposób, to zostało dodane jak do prototypu, a interpreter JavaScriptu,
kiedy wykona sobie instanceof Person, to oczekuje, że będzie to metoda
statyczna, więc tutaj napiszmy sobie static dodajemy to jako metodę statyczną. Ona
zawsze będzie zwracać false i jak widzisz teraz mamy false, a więc jeżeli sprawdzimy
czy employee jest instancją klasy Person, będzie zwrócone false. Natomiast
jeżeli byśmy sprawdzili czy jest instancją klasy Employee, będziemy mieli
zwrócone true, przynajmniej tak być powinno, ale tutaj pojawia się kolejna
rzecz, o której już ci mówiłem, czyli dziedziczenie statycznych metod. To oznacza,
że metoda hasInstance, tutaj dodana poprzez symbol,
została odziedziczona też przez employee. Dlatego tutaj, w tym konkretnym przypadku musielibyśmy
ją nadpisać. Ona tutaj też otrzyma obiekt i z nim
musimy zwrócić true or false, w zależności od tego czy obiekt jest tą instancją. Dlatego napiszmy,
jeżeli obj konstruktor równa się employee,
czyli jeżeli konstruktor tego konkretnego obiektu kieruje na employee, to
wtedy będziemy chcieli zwrócić true, więc return po
prostu, w ten sposób, ten operator porównania, zwróci true lub false. Raz
jeszcze sprawdźmy i teraz widzimy, że mamy tutaj true przy takim zapisie,
ale przy zapisie person, zobaczmy. Już będziemy mieli false.
Jak zatem widzisz, te well-known symbols pozwalają nam wpływać
na to, jak się zachowuje interpreter języka JavaScript, na przykład przy
takich operatorach jak instanceof. Nie mieliśmy takiej możliwości wcześniej, w przypadku
jako EcmaScript5. Zerknijmy sobie na górę jeszcze, jakie tutaj mamy
inne symbole, mamy toPrimitive i toStringTag, więc będę chciał
ci teraz te dwa z nich pokazać. Więc jeżeli byśmy sobie chcieli
dodać symbol toStringTag i pytanie, co on robi. Otóż spróbujmy
sobie zrobić console.log, w którym chcielibyśmy coś dodać, czyli
na przykład jaki string i napisalibyśmy Obiekt
to i do tego chcielibyśmy dodać nasz employee, employee1.
Co się stanie, jeżeli w takim przypadku, do stringu będziemy chcieli dodać nasz obiekt. Zobaczmy,
zostanie tutaj dodany object Object. No i tak jest domyślnie właśnie
w języku JavaScript, że coś takiego zostanie wtedy zwrócone, ale możemy wpłynąć
na to co jest podane w tym miejscu, bo są biblioteki, które po prostu sobie sprawdzają
czy na przykład, taki obiekt zwrócony, jeżeli się na nim wykona taką
metodę, bo w zasadzie dokładnie to samo by się stało, gdybyśmy wykonali metodę toString.
Zobacz, też nam zwróci object Object, ale przy dodawaniu do string'u samo
się to stało, więc są różne biblioteki, które sprawdzają na przykład czy to co tutaj zostaje
zwrócone czy tutaj jest Object czy jest na przykład coś innego. Więc my
możemy do naszej klasy sobie dodać co ma być w tym miejscu zwracane i możemy
to dodać za pomocą właśnie symbolu, który się nazywa toStringTag. Dodalibyśmy
sobie to tutaj za pomocą takiej wyliczonej właściwości i chcielibyśmy,
żeby to zwracało, w tym przypadku, Person. Natomiast
samo to nam nie zadziała, zobaczymy. Dalej jest to object Object, bo
to musi być ustawione jako getter, czyli tu musi być napisane get. Jeżeli jeszcze
nie wiesz jak działają gettery, to jest akurat coś co było w EcmaScript 5. To w
tym kursie, poniżej znajdziesz też lekcje w przypadku Proxy API gdzie
w jednej lekcji tłumaczę na szybko jak działają gettery w ES5. Natomiast taki
getter musielibyśmy dodać i wtedy okazuje się że object Person zostanie
zwrócone. Możemy jednak jeszcze dodać sobie inną rzecz,
czyli toPrimitive i ta metoda, którą sobie tutaj dodamy, też
będzie to getter, Symbol toPrimitive. Ona się będzie wywoływać
za każdym razem, kiedy w takim kontekście prymitywnym zostanie
użyty nasz obiekt, właśnie na przykład tutaj, czyli w tym miejscu interpreter próbuje
nasz obiekt skonwertować do wartości prymitywnej i domyś;lnie, jak widziałeś,
jest robione coś takiego, jak tutaj widzieliśmy object i
było Object. Ten string tak mogliśmy zmienić, ale jeżeli w ogóle całe
to zachowanie chcemy zmienić, to możemy tutaj coś zwrócić. Więc w tym miejscu, powiedzmy, że zwrócimy
sobie sayHello, czyli return this sayHello. Różne
obiekty możesz tworzyć i zależy co chcesz zwrócić. Jeżeli ktoś spróbuje
w takim kontekście tekstowym, na przykład, użyć twojego obiektu. W tym przypadku dla
próby zróbmy sobie coś takiego. Okej, pojawia nam się błąd w linijce 65.
Zobaczmy, jest to dokładnie tutaj, więc to oznacza, że coś zrobiłem
nie tak. Okej, już wiem, w tym przypadku to nie powinien
być getter, więc tutaj na to należy uważać. Jest to zwykła metoda i zobaczymy, teraz
obiekt to i mamy tutaj nazywam się Jan Kowalski, pracuje jako programista, więc
jak zatem widzisz, te symbole pozwalają nam w taki niskopoziomowy
dostęp do tego co dzieje się w różnych momentach wykonywania
takiego kodu JavaScript. Czyli wcześniej na przykład nie mogliśmy wpłynąć na to co
się dzieje kiedy mamy użyte na naszym obiekcie instanceof. Teraz
mamy na to wpływ. Podobnie możemy zmienić ten tag za pomocą właśnie toStringTag lub możemy
nawet nadpisać w ogóle co się dzieje kiedy ktoś będzie chciał użyć naszego
obiektu jako wartości prymitywnej. Jak widzisz, interpreter robi sobie to automatycznie,
na przykład, przy takiej operacji, ale teraz mamy na to wpływ. Zerknijmy na
szybko jeszcze na pozostałe symbole. Mamy jeszcze isConcatSpreadable i on
polega na tym, że jeżeli chcielibyśmy naszej, z naszego obiektu korzystać,
jak z tablicy, czyli na przykład mielibyśmy jakąś jedną tablicę, chcielibyśmy połączyć
ją z naszym obiektem, który byłby tutaj. To jeżeli nasz obiekt
miałby indeksy numerowane od zera i właściwość length i pod symbolem
isConcatSpreadable dodali byśmy mu true, żeby zwracało wartość true,
to wtedy, jeżeli na innej tablicy użyjemy concat i spróbujemy
dodać do tego nasz obiekt, to poszczególne jego indeksy zostaną właśnie rozstrzelone
jako 01 i tak dalej i tak dalej. Gdybyśmy takiego symbolu nie
dodali, to wtedy normalnie cały ten obiekt byłby jako jeden element dodany
do tamtej tablicy. Jeśli chodzi o symbol species to on pozwala
nam wpływać na to, co będzie zwrócone jeżeli skorzysta się z jakiejś nowej metody. Teraz
ci przypomnę, że jeżeli dziedziczyliśmy sobie z klasy array, czyli z wbudowanego typu,
to kiedy na tej naszej nowej klasie Collection, być może to pamiętasz, skorzystaliśmy
ze slice, to został zwrócony nowy obiekt naszej klasy Collection,
a nie array i to właśnie można kontrolować za pomocą symbol species. Jeśli
chodzi o kolejną linijkę, czyli match, replace, search, split to pozwala nam
to tworzyć własne klasy, w których jeżeli za pomocą takich symbolów dodamy metody,
to obiekty naszej klasy będziemy mogli wykorzystywać wszędzie tam gdzie
można było wykorzystać wyrażenia regularne. Zauważ, że te
metody to są metofdy string'u, którym przekazuje się wyrażenie regularne, więc teraz zamiast
wyrażenia regularnego będzie można przekazać nasz obiekt, z naszej klasy, pod warunkiem,
że on będzie którąś z tych metod sobie zawierał. Symbol unscopables
z kolei, pozwala nam powiedzieć które z właściwości obiektu mają być pomijane,
kiedy korzystamy z takiego, z takiej konstrukcji with, która jest niezwykle rzadko
w JavaScripcie wykorzystywana i nie jest polecane jej użycie. Jeśli jednak korzystałbyś
z with i nie chciałbyś, aby w tym bloku kodu pewne rzeczy to się znajdowały,
pewne właściwości obiektów, to możesz je zapisać pod Symbol unscopables
i ostatni, jest to symbol iterator. Nie będę go teraz tłumaczył
dlatego, że będziemy z iteratorów już wkrótce w tym kursie korzystać i jest
to, wydaje mi się symbol, z którego najczęściej będziesz korzystał. Ja również najczęściej z niego
korzystam. Jest to rzecz absolutnie świetna. Dlatego, jak
widzisz mamy wiele symboli wbudowanych. Na wiele niskopoziomowych czynności one
nam pozwalają, ale to nie oznacza, że większość z nich jakoś szczególnie będzie dla przydatne. Natomiast
symbol iterator na pewno będzie o czym wkrótce się przekonasz.