w Praktyce
9 godz. 47 min · JavaScript · Full-stack i Programowanie
Piotr PalarzWeb DeveloperW pierwszym rozdziale tego kursu poznasz bardzo dokładnie koncepcje programowania zorientowanego obiektowo. W jednej z lekcji, omówimy wszystkie z nich na przykładzie pseudo-kodu, niezwiązanego bezpośrednio z językiem JavaScript. Dzięki temu zrozumiesz, jak realizowane jest programowanie obiektowe w wielu popularnych językach programowania. Dowiesz się czym jest klasa, obiekt, instancja, właściwości, metody, a także zrozumiesz takie pojęcia jak dziedziczenie, polimorfizm, abstrakcja czy enkapsulacja. Następnie przejdziemy już do języka JavaScript i do zrozumienia tego, w jaki sposób powyższe koncepcje są w nim zaimplementowane. Język ten nie jest bowiem w 100% klasycznie obiektowy, jak np. język PHP. Co jednak bardzo istotne, JavaScript implementuje tzw. dziedziczenie prototypowe, którego bardzo dogłębne zrozumienie, gwarantuje zrozumienie całego języka JavaScript. Dowiesz się zatem czym są konstruktory i jak je tworzyć, a także jak korzystać z prototypu funkcji. Dzięki temu będziemy mogli wykorzystać obiektowość do własnych celów, co później w praktycznych przykładach uczynimy.Na przestrzeni kilku lekcji zobaczysz krok po kroku, jak w języku JavaScript zaimplementować dziedziczenie wielokrotne. Taka wiedza absolutnie otwiera oczy na zależności rządzące obiektami w tym języku. Dowiesz się również jak rozszerzać wbudowane konstrukcje języka JavaScript czy Obiektowego Modelu Dokumentu, a także kiedy powinniśmy to robić. Omówimy problemy, jakie mogą się pojawiać przy korzystaniu ze słowa kluczowego this, a także sposoby ich rozwiązania. Poznasz 3 bardzo ważne metody funkcji: call, apply i bind.JavaScript ma wiele specyficznych cech, a jedną z nich są tzw. domknięcia. W jednym z rozdziałów zobaczysz, do czego one służą i kiedy powinniśmy z nich korzystać. Dopełnimy tym również wiedzę związaną z programowaniem obiektowym i tzw. prywatnością.Rozdział o obiektowości został celowo umieszczony na samym początku kursu, gdyż zrozumienie tych koncepcji pozwala patrzeć zupełnie inaczej na wszystkie pozostałe. Po tym rozdziale przejdziemy do omówienia bardzo popularnego, lekkiego formatu wymiany danych JSON. Dowiesz się jak wygląda składnia tego formatu, a także jak współpracuje on z językiem JavaScript.Następnie przejdziemy do bardzo ekscytującego tematu, jakim jest technologia AJAX. Dzięki niej możemy wysyłać zapytania do serwera i pobierać dane, bez przeładowywania witryny. Do zrozumienia AJAXa niezbędne jest jednak rozumienie działania protokołu HTTP, na którym opiera się sieć www. Z tego powodu, jedna z lekcji została w 100% poświęcona HTTP i dowiesz się z niej jak wysyłane są żądania i odpowiedzi, a także tzw. nagłówki, które będą dla nas niezwykle istotne. Chwilę później omówimy również bardzo ważne mechanizmy: Same- origin policy i CORS, które blokują możliwość wysyłania żądań AJAX do pewnych serwerów. Kiedy już będziesz rozumiał te niezwykle istotne koncepcje, przejdziemy do napisania pierwszego kodu, wysyłającego asynchroniczne żądanie do serwera. Następnie dowiesz się jak wysyłać, a także odbierać dane z serwera, umieszczać je na stronie oraz śledzić postęp zarówno wysyłania, jak i pobierania danych.W tym rozdziale na przestrzeni kilku lekcji napiszemy swoją własną bibliotekę AJAX, która pozwoli w niezwykle łatwy sposób wysyłać i odbierać dane. Skorzystamy w niej już w kolejnej lekcji, gdzie zobaczysz, jak wysłać wiadomość e-mail z użyciem AJAX i PHP po stronie serwera. Gotowy skrypt, będziesz mógł umieścić na własnej stronie internetowej. Na zakończenie tego rozdziału omówimy również dokładnie niezwykle sprytną technikę o nazwie JSONP, które pozwala wysyłać tzw. żądania “cross-origin”. Przekonasz się dlaczego taka technika powstała i jak współpraca klienta i serwera potrafi obejść zabezpieczenia przeglądarek.Kolejnym tematem omówionym w kursie będą Cookies, czyli tzw. ciasteczka. Dowiesz się czym są, w jakim celu istnieją, a także jak są ustawianie przez serwer. Co ciekawe, również z poziomu języka JavaScript będziemy mieli do nich dostęp, a zatem zobaczysz jak je ustawiać i odczytywać. Na tym etapie przyda nam się wiedza zdobyta w lekcji o protokole HTTP.W kursie znajdziesz również rozdział poświęcony w 100% wyrażeniom regularnym. To mechanizm języka, który pozwala dopasowywać tekst do definiowanych przez nas wzorców. Wyrażenia regularne potrafią być bardzo zaawansowane i odstraszać, dlatego rozłożymy je na czynniki pierwsze, byś dokładnie je zrozumiał. Na przestrzeni wielu lekcji dowiesz się jakie są specjalne symbole wykorzystywane przy wyrażeniach regularnych, czym są kwantyfikatory, kotwice czy np. grupowanie. Następnie przejdziemy do wykorzystania wyrażeń regularnych w języku JavaScript. Poznasz zarówno metody obiektu RegExp jak i te dostępne na obiekcie String. Dzięki nim będziemy mogli wyszukiwać np. adresów e- mail w podanym tekście, usuwać je lub zamieniać na coś innego. Jako praktyczny projekt, stworzymy “Antybluzgacz”. Wykorzystamy do tego celu programowanie obiektowe, a sama aplikacja będzie pozwalała filtrować wpisywany przez użytkownika tekst wiadomości i wyłapywać w nim niecenzuralne słowa. Wszystkie z nich zamienimy na przypadkową reprezentację znaków, np. $#!@%^. Ten projekt pokaże Ci nie tylko jak korzystać z wyrażeń regularnych, ale także jak profesjonalnie pracować z kodem JavaScript.W przedostatnim rozdziale tego kursu znajdziesz lekcje związane z dobrymi praktykami pracy. Omówimy tzw. “strict mode” języka JavaScript, zagadnienia związane z minifikacją i konkatenacją skryptów, sprawdzaniem poprawności pisanego kodu oraz delegacją zdarzeń DOM.Na końcu kursu znajdziesz 10 krótkich lekcji z serii Tips & Tricks, które przybliżą Ci wiele ciekawych konstrukcji języka JavaScript, a także technik na rozwiązanie różnych problemów. Zobaczysz np. jak wczytać obrazy w tle czy jak wyświetlić na pasku tytułowym witryny migające powiadomienie.Podsumowując, kurs ten jest dopełnieniem wiedzy z zakresu języka JavaScript i Obiektowego Modelu Dokumentu z kursu “JavaScript od Podstaw”. Poprzedni kurs nie jest wymagany, lecz jego przerobienie z pewnością pozwoli dużo lepiej przyswoić wiedzę z tego kursu, gdyż były one przygotowywane równocześnie. Oba te materiały, pozwolą od zera, wskoczyć na naprawdę wysoki poziom rozumienia języka, a także dobrych praktyk pisania kodu.
Do tego kursu mogą jednak przystąpić wszystkie osoby, które znają już podstawy języka HTML, CSS i JavaScript i chcą poszerzyć swoją wiedzę, a także spojrzeć zupełnie inaczej na ten język.
Mam nadzieję, że na tym etapie już rozumiesz, jak działa dziedziczenie prototypowe w JavaScript, bo jest to
kluczem do zrozumienia tego języka i że teraz już wiesz, że kiedy na tablicach korzystamy z jakichś metod,
to są one wyszukiwanie w prototypie tablicy. Jeżeli ich tam nie ma, to w Object.prototype. Mam nadzieję, że
już ten łańcuch zrozumiałeś
i skąd to wszystko się bierze.
Natomiast teraz będę chciał ci pokazać, że możemy również tworzyć własne konstruktory.
Do tej pory powiedziałem ci, że Array, pisane z dużej litery, to jest funkcja, podobnie jak Object itd.
i możemy używać operatora new, aby takie nowe obiekty tworzyć.
Więc teraz będę chciał ci pokazać, jak zrobić własne, bo będzie to dla nas bardzo przydatne.
Przejdziemy sobie do skryptu i na początek utworzę funkcję, którą nazwę Person. W ten sposób. Mamy pustą funkcję.
Dlaczego napisałem Person z dużej litery?
Nie ma to jakiegokolwiek znaczenia w języku JavaScript, oprócz konwencji - czyli programiści przyjęli taką
konwencję, że z dużej litery piszemy wtedy, kiedy to będzie konstruktor, czyli jak gdyby klasa.
Ja jeszcze będę nawiązywał do tej lekcji, która była na początku tego rozdziału o programowaniu zorientowanym
obiektowo i pokażę ci, które z tych koncepcji, które tam pokazywałem, np. klasa, jak przekładają się na język
JavaScript. Bo nie bez powodu ta lekcja tam się znalazła. Więc pamiętaj, że z dużej litery nazywamy funkcje -
jeżeli to nie będą takie zwykłe funkcje, jak do tej pory w JavaScript pisaliśmy, które coś tam robią, ale
jeżeli będą to funkcje, które mają posłużyć jako konstruktor. Natomiast co jest niezwykle istotne,
już stworzyliśmy sobie taką funkcję.
Nie ma najmniejszego problemu, ona w przeglądarce dla nas będzie widoczna pod Person. Co jest bardzo ciekawe,
to od razu ma ona swój prototyp, nic nie zrobiliśmy i jest to obiekt, w którym mamy konstruktor i jest
to funkcja. Pokazywałem to w prezentacji, że jeżeli utworzymy nową funkcję, to ma ona prototyp.
Pamiętaj, to jest zwykły obiekt i w tym obiekcie mamy właśnie coś takiego jak konstruktor, który kieruje
znowu na tę funkcję.
Mamy tutaj również proto,
to co pokazałem ci lekcji poprzedniej. I to proto, to jest prototyp tego obiektu, czyli pod Person.prototype
znalazł nam się obiekt, który dalej swoim proto kieruje na Object.prototype. Czyli taki łańcuch już nam się
utworzył, że mamy nasz Person.prototype, w ten sposób. I jeżeli w nim czegoś nie znajdziemy, co będziemy wyszukiwać,
to następnie będzie Object.prototype. Czyli podobnie jak mieliśmy wcześniej Array.prototype i następnie
Object.prototype.
Mam nadzieję, że to jest jasne, ale o tym będę mówił więcej w kolejnej lekcji. Czyli utworzyliśmy pustą
funkcję i można powiedzieć, wszystko gra.
Natomiast przypomnę ci może na samej górze, że mogliśmy nową tablicę stworzyć za pomocą zapisu new
Array. Array
to też była funkcja, ona też miała swój prototyp i tak dalej.
Czyli teraz stworzyliśmy sobie nową tablicę, więc nic nie stoi na przeszkodzie, aby z naszej funkcji skorzystać
dokładnie w taki sam sposób. Napiszemy
person1 i new Person.
Może to się wydawać teraz dziwne, bo do tej pory, jeżeli nie korzystałeś wcześniej z tego programowania
obiektowego, tego nie widziałeś. I również w pierwszej części tego kursu takiego zapisu nie było,
oprócz np. new Array, ale jest to poprawny zapis w języku JavaScript. I teraz mógłby się zastanowić, co
jest tutaj. Zerknijmy, person1.
W zasadzie nie wiemy, co to jest.
Zostało to wyświetlone jako obiekt takiej klasy Person jak gdyby.
No, zobaczmy może dir, dir(person1), Person i nic tam nie ma.
Mamy tam tylko prototyp. Więc co to tak naprawdę jest? Może wpiszmy typeof person1.
I tutaj zaczynamy rozumieć, co to jest.
Jest to obiekt. Tak jak w JavaScript wszystko jest obiektem, tak person1 też jest obiektem. Z tego zapamiętaj
jedną niezwykle ważną rzecz, że Person to jest funkcja. Tylko na funkcjach możemy używać new. Każda funkcja
ma .prototype, czyli swój prototyp. I teraz co jest szalenie istotne - zawsze, zawsze kiedy użyjemy
na funkcji new, czyli new Person, to co zostanie zwrócone, to jest obiekt - to zawsze będzie obiekt. To nigdy
nie jest jakaś funkcja i tak dalej. To zawsze jest obiekt.
Mimo tego, zauważ - i to też jest również istotne -
nie wpisaliśmy tutaj return. Nie ma żadnego polecenia return, czyli pusta funkcja, na której użyliśmy takiego
zapisu,
zwróciła nam tutaj obiekt.
Teraz chciałbym zauważyć, co stanie się - jeszcze o tym będę mówił w tym kursie - jeżeli nie będzie słowa
new. Na tym etapie powinieneś wiedzieć, że funkcja tu może robić dowolne rzeczy. Może nic nie robić. Jeżeli
nie zwróci nic, to zwraca undefined, czyli w tym przypadku person1, jeśli sobie zrobimy typeof, to jest
undefined. Bo wywołaliśmy sobie tutaj jakąś funkcję, która nic nie zwróciła, czyli zwróciła undefined i to co
zwróciła właśnie - to undefined - zostało tu przypisane.
A jeżeli użyjemy new, to ten sam operator typeof na tej samej zmiennej zwróci nam object.
To jest bardzo ważne.
Teraz przejdźmy sobie dalej, bo chcę ci pokazać, że tutaj będziemy mogli podawać różne parametry, jak to do funkcji. Nie ma
najmniejszego problemu. Napiszmy sobie tutaj firstName oraz lastName.
W ten sposób. To oznacza, że tworząc taką nową instancję, to możemy traktować jako klasę -
w zasadzie to, co jest tutaj. Jeżeli byś sobie wrócił na spokojnie do lekcji, gdzie obawiałem wszystkie paradygmaty
programowania obiektowego, to tam mówiłem o klasie. Czyli klasa jest takim schematem i w JavaScript nie mamy takich
standardowych klas, ale to możemy porównać do klasy. Taki zapis. To możemy tutaj przekazać pewne parametry
i możemy je zapisać tutaj wewnątrz, czyli tworząc nową osobę,
przekażmy je tutaj, tak jak do zwykłej funkcji. Napiszmy sobie może Jan Kowalski.
W ten sposób - Jan Kowalski. To wiesz, że to będzie tu pod firstName
i lastName. Natomiast aby to mogło być w tym obiekcie zapisane, to musimy sobie to zapisać wewnątrz tego obiektu.
I tutaj właśnie na ten konkretny obiekt kieruje słowo kluczowe this. Czyli this nie kieruje jakoś na
tę klasę w żaden sposób. Również o tym mówiłem w lekcji wprowadzającej.
This będzie za każdym razem gdzie indziej kierować. W tym przypadku na ten nowy obiekt, który tutaj tworzymy.
Czyli this.
I tutaj skoro jest to obiekt, bo ja już ci już o tym mówiłem, person1, to możemy po kropce się odwołać i napisać
sobie firstName, powiedzmy Jan.
Nie ma problemu, żadnego.
Teraz person1 będzie miał tutaj firstName Jan. Czyli wyobraź sobie, że this kieruje właśnie na ten nowo utworzony
obiekt. Dokładnie w ten sam sposób. Czyli mogę napisać this.firstName. I tutaj żeby cię to nie zmyliło,
to absolutnie nie musi się nazywać tak samo jak parametr. To jest nazwa parametru, czyli jest to lokalna
zmienna widoczna wewnątrz, a to jest nazwa właściwości, którą przypisuję do obiektu. Więc mogę tu napisać fName.
Może zróbmy to w ten sposób, żeby cię to nie myliło. Równa się firstName. Czyli chcę zapisać w
obiekcie właściwość fName, która jest równa temu, co ktoś przekazał w tym miejscu. Czyli Jan i zróbmy
to samo z lastName. Napiszemy lName równa się lastName. Ok. Teraz tworząc nowy obiekt, możemy to przekazać.
Jeżeli to zrobimy i tutaj sobie odświeżę. Przejdziemy do person1, to okaże się, że ma on firstName i lastName.
I jak każdy obiekt w JavaScript, gdyby to był taki zwykły, utworzony obiekt,
możemy się odwołać do person1.fName, nie ma problemu. Nawet możemy to zmienić w dowolny sposób i to też
jakby nie jest nic dziwnego.
Natomiast zauważ, w jaki sposób właśnie utworzyliśmy nowy obiekt.
Teoretycznie zrobiliśmy to podobnie, jak gdyby nie używać tutaj new, ale wywołać tę funkcję i jakby ta
funkcja nam zwracała powiedzmy return - obiekt, który miałby fName równy firstName i lName równe lastName. Prawda?
Jeżeli to sobie wykomentujemy w tym momencie,
to tutaj person1 wygląda tak samo. Ale zauważ, że teraz jest to object, a nie person. Wcześniej tutaj było napisane
person. Więc teoretycznie to wygląda tak samo, ale to nie jest to samo.
I tutaj można jakby różnie na to patrzeć, dlatego że ja mówię w JavaScript, że wszystko jest obiektem, ale taki obiekt
też nazywamy obiektem. Natomiast ja już wspominałem, że w niektórych językach programowania taki obiekt,
w którym mamy właśnie klucz-wartość, klucz-wartość, jest nazywany tablicą asocjacyjną.
Więc jakby tutaj trzeba to też umieć rozróżnić. To jest taka powiedzmy tablica asocjacyjna, która sama w sobie też
jest obiektem, bo możemy do niej różne rzeczy dodawać. Ale jak utworzę sobie tablicę, to też mogę przecież po
kropce do niej coś dodać, a nie jest ona w ten sposób zrobiona, jak właśnie taka tablica asocjacyjna,
gdzie jest klucz i wartość. Natomiast widzisz, że jeżeli nie użyliśmy new, tylko coś zwróciliśmy, to tutaj teoretycznie
mamy to samo.
Ale ja to wykomentuję. Znowu użyjemy new, bo to jest bardzo ważne. To odkomentuję i
raz jeszcze zerkniemy do person1 i teraz jest to person.
Dzięki temu będziemy mogli korzystać z prototypu i jeszcze kilku innych rzeczy - o tym będę mówił dalej.
Natomiast chcę utworzyć drugą osobę, bo na tym polega programowanie obiektowe, które omawiamy, że mamy taką
ogólną klasę, która mówi nam - tutaj będzie firstName i lastName. No, ale żeby w każdym obiekcie te dane były
unikalne, to musimy je unikalnie podawać właśnie tutaj, czyli np. Tomasz Nowak.
I teraz mamy person1 i person2 - person1, person2.
Oba mają taką samą jakby klasę.
I wyglądają inaczej, czyli każdy ma z nich swoje dane.
W ten sposób nowe obiekty możemy tworzyć. I teraz chcę ci powiedzieć o rzeczy, która również jest ważna.
Gdybyś znowu chciał sobie wrócić do lekcji, gdzie wprowadzałem do programowania obiektowego, mówiłem o klasie.
Więc to możesz traktować jako klasę. Jest to taki schemat, na podstawie którego tworzymy nowe instancje,
czyli tworzymy obiekty - w ten sposób - na podstawie klasy, przekazując odpowiednie dane, tworzymy nową instancję,
czyli obiekt.
Mam nadzieję, że to jest jasne.
Natomiast wspominałem, że w językach zorientowanych obiektowo, również mamy coś takiego jak konstruktor
i konstruktor to była taka specjalna funkcja, która się wywoływała wtedy, kiedy była tworzona nowa instancja.
W JavaScript bezpośrednio tak jakby nasza klasa jest tym konstruktorem.
Zauważ, że wywołując new Person, przekazuję tutaj Jan Kowalski i od razu to jest w tym miejscu, a nie wpisujemy tutaj
jakiejś specjalnej metody, którą np. nazywamy construct, tak to wygląda w PHP i nie piszę, że to jest
funkcja, która przyjmuje firstName i lastName. Bo tak by to powiedzmy wyglądało w języku PHP. I to, co mamy tutaj,
musielibyśmy wkleić w tym miejscu.
Wtedy nie mielibyśmy tych parametrów tutaj, tylko przekazując je tutaj do new Person, one byłyby wrzucane
specjalnie do tej funkcji construct i ona by coś robiła.
Mam nadzieję, że jakby teraz to rozumiesz. A my te parametry mamy w tym miejscu.
Czyli jakby samo Person to jest klasa, taki schemat obiektów, które będą tworzone. Przy okazji zachowuje
się też jak konstruktor, bo kiedy przekazujemy tu dane, nie są przekazywane takiej specjalnej funkcji,
tylko właśnie bezpośrednio w tym miejscu i możemy je zapisać w obiekcie. Na sam koniec chcę ci pokazać
jeszcze jedną rzecz, że skoro to jest obiekt, skoro możemy do niego przypisywać właściwości jak do każdego
innego obiektu w JavaScript, to możemy przypisać metodę sayHello.
Będzie to funkcja, w ten sposób. I chcielibyśmy, żeby ona zwracała return this - bo nie możemy inaczej się
do tych zmiennych tutaj odwołać. Czyli this.fName +.
Chciałbym, żeby tutaj była spacja, thislName.
Czyli będziemy mieli nowe utworzone obiekty. Ten będzie miał Jan Kowalski i kiedy na niej wywołamy sayHello,
to zwróci nam właśnie Jan Kowalski.
Tak to powinno zadziałać,
więc możemy sobie to sprawdzić.
Person1 i tutaj napiszemy sayHello.
Zobacz, Jan Kowalski, a person2,
sayHello,
Tomasz Nowak. Świetnie to zaczyna działać i myślę, że zaczynasz widzieć zalety programowania obiektowego.
Natomiast jest tutaj jedna wada tego rozwiązania, które teraz zrobiliśmy.
Fakt, że ta funkcja, która tutaj się znajduje, jest powtarzana za każdym razem, gdy tworzymy nowy obiekt.
O ile to chcemy, aby było unikalne, o tyle ta funkcja, zauważ, ona się nie zmienia - czy to będzie Jan Kowalski,
czy to będzie Tomasz Nowak.
To nie ma znaczenia, ona zawsze jest taka sama.
A teraz tworząc tutaj poprzez new Person nowy obiekt, utworzyliśmy nowy obiekt, który ma unikalne właściwości
plus
stworzyliśmy taką funkcję, która znajduje się pod obiekt sayHello.
Ta funkcja została zapisana w pamięci komputera.
Tutaj utworzyliśmy kolejny obiekt i znowu ma on unikalne dane.
To jest w porządku, ale znowu utworzyliśmy taką samą funkcję. Czyli teraz pamięci komputera są dwie funkcje,
które robią dokładnie to samo. Poprzez this
one się mogą odwoływać do obiektu, więc one robią dokładnie to samo. I teraz co by było, gdybyśmy utworzyli
sto takich obiektów, może tysiąc, może 10 tysięcy, w zależności od tego, co robimy.
Byłoby to bez sensu, bo każdy taki obiekt miałby własną funkcję, która wygląda tak samo.
Dlatego w kolejnej lekcji pokażę ci, jak możemy sobie z tym problemem poradzić.
Na sam koniec chcę ci pokazać tylko jeden jeszcze bardzo ciekawy operator, który jest dostępny w języku
JavaScript i nazywa się instanceof.
I jeżeli byśmy tutaj chcieli wpisać person1 instanceof. Mówiłem ci, że person1 to jest instancja utworzona jakby
z klasy. W JavaScript to nazywamy konstruktorem. Natomiast przypominam raz jeszcze, że konstruktor to jest
specjalna metoda klasy, która się wywołuje wtedy, kiedy jest tworzony nowy obiekt. Ale w JavaScript to się
nazywa konstruktor.
Możemy o tym mówić zamiennie klasa,
czyli jeżeli person1 jest instancją tej klasy, to mamy operator, który nam to pozwala sprawdzić - person1
instanceof Person. W ten sposób. Mamy true,
czyli person1 jest instancją klasy jakby Person.
Podobnie jeżeli byśmy stworzyli nową tablicę i napisali instanceof Array, to się okaże, że to też jest true.
Natomiast jeżeli napiszemy instanceof Object, okaże się również, że jest to true. I być może pamiętasz, jak w
poprzedniej lekcji pokazywałem ci właśnie, że jeżeli sprawdzimy Object.prototype.isPrototypeOf Array, okaże
się że tak.
I podobnie będzie z tablicą. Czyli zarówno tablica dziedziczy z Array.prototype, jak i z Object.prototype.
I ten operator również nam to pokazuje. Czyli tablica jest z instancji obiekt, ale także Array.