od Podstaw
1 godz. 54 min · Typescript · Full-stack i Programowanie
Adam GospodarczykZacznijmy od tego, że JavaScript jest dynamicznie typowany. Oznacza to, że typy zmiennych mogą się zmieniać w czasie wykonywania programu, a my nie mamy nad nimi kontroli. A po co nam ta kontrola? Między innymi po to, aby przypadkowo nie dodać typu number do string lub przekazać do funkcji nieprawidłowe danych. Ogromną zaletą jest to, że o tego typu błędach dowiadujemy się już na etapie pisania kodu a nie dopiero w trakcie jego wykonywania... na produkcji.
Prawdopodobnie znasz mechanizm intellisense, czyli inteligentnego podpowiadania kodu przez edytor. Pisząc kod w TypeScript, tworzysz definicje typów dotyczących Twojej aplikacji. W ten sposób dostęp do definicji klas i właściwości obiektów masz właściwie na wyciągnięcie myszki. Wystarczy "hover" na funkcji aby uzyskać szczegółowe informacje, które pomogą Ci w pisaniu kodu. Oprócz tego otrzymasz również automatyczne podpowiedzi w trakcie dostępu do właściwości i metod. Nic tylko pisać kod!
Nie musisz przepisywać całego projektu. TypeScript stanowi nadzbiór JavaScriptu. Zatem cały Twój projekt jest z nim w 100% kompatybilny, a Ty możesz stopniowo dodawać definicje typów. Nawet nie będziesz wiedział kiedy typy pojawią się w całej Twojej aplikacji. To daje Ci również możliwość uczenia się TypeScriptu w trakcie jego wdrażania. W tym kursie opanujesz podstawy a później... sam zobaczysz!
Ten kurs został stworzony z myślą o programistach, którzy podstawy JavaScriptu mają już za sobą i chcą poznać zalety statycznego typowania oferowanego przez TypeScript. Na początku Kursu zaczynamy również od krótkiej powtórki najważniejszych elementów samego JS.
3.8+
Bez wątpienia w nauce TypeScriptu ogromną
rolę odgrywa fakt jak dobrze znamy sam JavaScript.
Dlatego w tej lekcji zrobimy sobie szybką powtórkę z elementów, które mogą nam się
przydać. I pierwszym takim tematem jest porównywanie wartości.
W JavaScripcie możemy w tym celu wykorzystać operator porównania i wtedy porównujemy
same wartości z pominięciem typów, oraz operator ścisłego porównania.
W takiej sytuacji poza wartością zmiennej porównujemy również jej typ.
Spójrzmy jednak na ten przykład.
Mamy tutaj pusty ciąg znaków oraz zero.
Te wartości oczywiście nie są sobie równe,
ale już w momencie gdy sytuacja wygląda tak, otrzymujemy błędny wynik.
Wynika to z faktu, że zarówno pusty ciąg
znaków, jak i zero będące cyfrą, są postrzegane przez JavaScript jako tzw.
falsy values, o których powiemy sobie za chwilę.
W każdym razie wyjściem z takiej sytuacji jest korzystanie z operatora ścisłego
porównania za każdym razem gdy porównujemy jakieś wartości.
Wyjątek tutaj stanowi wyłącznie porównywanie do
wartości null, ale do tego również jeszcze wrócimy.
Drugim tematem, którym warto poruszyć są typy proste i referencyjne. W JavaScripcie
możemy przypisywać wartości do zmiennych oraz zmienne do innych zmiennych.
Więc teraz skoro przypisaliśmy x do y, wartość zmiennej x pozostaje równa 10 oraz wartość
zmiennej y również zostaje ustawiona na 10.
Jednak teraz skoro y równa się x to
teoretycznie wartość x również powinna się zmienić.
Tak oczywiście się nie stało, ponieważ
tutaj mamy przypisanie wartości, a nie referencji do tej zmiennej.
Ale już w sytuacji gdybyśmy do naszej
zmiennej przypisali typ referencyjny, taki jak chociażby obiekt, to w momencie przypisania
go do innej zmiennej i powiedzmy zmiany jakiejś właściwości tego pierwszego
obiektu, to ta właściwość będzie dostępna również w referencji.
Oczywiście możemy to teraz nawet potwierdzić, ściśle porównując te zmienne.
W tym wszystkim trzeba pamiętać jeszcze o tym, że jeżeli tworzymy dwa nowe obiekty a
następnie porównamy je ściśle ze sobą to nie będą sobie równe.
I to jest właśnie coś o czym warto pamiętać.
Dodam tylko, że referencyjnymi typami danych w JavaScripcie są obiekty, tablice oraz funkcje.
Następne w kolejce są wartości null oraz unidefined.
Wartości te, w sytuacji gdy nie porównujemy ich ściśle, są sobie równe i to jest
właśnie przykład, o którym mówiłem wcześniej.
W każdym innym przypadku powinniśmy korzystać z operatora ścisłego porównania.
Natomiast w momencie, gdy sprawdzamy czy wartość jest nullem lub undefined, wtedy
zdecydowanie lepiej korzystać z operatora porównania.
Swoją drogą różnica pomiędzy null a undefined
jest taka, że wartość undefined przyjmują zmienne, które zostały zadeklarowane,
natomiast żadna wartość nie została
jeszcze do nich przypisana. A null reprezentuje dosłownie nic
i jest to wartość wykorzystywana przez programistę.
Tutaj zdecydowanie warto wiedzieć, że w momencie gdy porównujemy jakąś zmienną do
tych wartości, nie musimy martwić się o tzw.
falsy values, ale tutaj wyjątek stanowi
porównywanie do niezagnieżdżonych elementów.
Czyli jeżeli mamy zmienną globalVar,
którą porównamy do undefined, otrzymujemy reference error.
Rozwiązaniem w tej sytuacji jest porównanie typów w następujący sposób.
Dzięki temu możemy być pewni, że
korzystając z tej zmiennej ona faktycznie jest do naszej dyspozycji.
Także raz jeszcze przypominam: do porównywania zmiennych korzystamy z operatora
ścisłego porównania, czyli trzech znaków równości, ale wyjątek stanowi moment w
którym porównujemy wartość do nulla lub undefined.
Kolejną bardzo istotną kwestią jest to, abyś dobrze rozumiał słowo kluczowe 'this'.
Szybko przypominając słowo kluczowe this
zależy od tego, w jaki sposób została wywołana funkcja.
Czyli inaczej mówiąc jaki był kontekst wywołania.
Dlatego też jeżeli zdefiniujemy funkcję zwracającą this, a następnie wywołamy ją w
globalnym kontekście to słowo kluczowe this będzie wskazywało na obiekt globalny.
Ale już jeżeli ta funkcja znajdzie się wewnątrz obiektu i wywołamy ją, odwołując
się do właściwości tego obiektu, to kontekst odpowiednio ulega zmianie
i mamy tutaj odwołanie do obiektu, który utworzyliśmy.
Jeżeli chodzi o słowo kluczowe this bardzo istotna jest jeszcze kwestia funkcji
strzałkowych, o których będziemy mówić za chwilę.
No i teraz czas na closure, czyli
domknięcia. Przypominając definicje domknięcia: występuje wtedy, gdy funkcja
zapamiętuje a następnie wykorzystuje swój leksykalny zakres,
nawet wtedy gdy jest wywoływana poza nim.
W praktyce oznacza to mniej więcej tyle, że jeżeli mamy funkcję, która posiada jakieś
informacje oraz funkcje, które wykorzystują te informacje, a następnie ta wewnętrzna
funkcja zostanie zwrócona to teoretycznie w momencie, gdy wywołamy funkcja outer,
jej działanie kończy się w tym miejscu i
garbage collector dba o to, aby usunąć tę informację. Ale w związku z tym, że
wykorzystujemy je również tutaj zostaną one przekazane jako closure, czyli inaczej
mówiąc dalej będą dla nas dostępne. Także mamy tutaj spełnioną naszą definicję,
czyli funkcja getInner posiada dostęp do swojego leksykalnego zakresu,
nawet wtedy gdy jest wywoływana poza nim.
No i to by było na tyle, jeżeli chodzi o domknięcia.
Być może ten prosty przykład wyjaśnił Ci tutaj coś jeszcze.
Tymczasem ostatni temat w tej lekcji to truthy oraz falsy various.
Chodzi tutaj o to, że gdy wykorzystujemy jakąś wartość w kontekście boolean, zostaje
ona zinterpretowana przez JavaScript właśnie w kontekście true lub false.
No i na przykład: wartość 1 jest postrzegana jako prawda.
Dlatego nasz console.log się wykona, ale już
w sytuacji, gdy będziemy mieć tutaj zero, warunek nie zostanie spełniony i console.log
nie zostanie wyświetlony. Aby się w tym wszystkim odnaleźć warto
zapamiętać teraz falsy values. Aby Ci je przedstawić wykorzystam operator.
Bang Bang.
Chodzi tutaj o to, że jeden wykrzyknik zamienia wartość na logiczną oraz
jednocześnie ją odwraca, więc drugi wykrzyknik ponownie ją odwróci i otrzymamy
informację o tym, jak zachowuje się zmienna w kontekście logicznym.
Oczywiście pusty string jest przykładem
falsy values, podobnie zresztą jak zero, not a number (NaN), null i undefined.
Tutaj jeszcze warto tylko zwrócić uwagę, że skoro pusty string jest postrzegany jako
falsy values, to czy tak samo dzieje się z obiektami oraz tablicami?
No i okazuje się, że nie. One akurat wartościami falsy nie są i z pewnością
warto o tym pamiętać, bo nie wiem jak Ty, ale mi zdarza popełnić się taki błąd.
No i jeżeli chodzi o powtórkę z JavaScriptu to byłoby na tyle. W przypadku gdyby któryś z
tych tematów nie był dalej dla Ciebie jasny,
zachęcam Cię do zapoznania się z kursem na temat samego JavaScriptu.
Tymczasem przechodzimy już do kolejnej lekcji.
Equality · 1 min
// Equality
1 == "1"; /*?*/
1 === "1"; /*?*/
"" == "0"; /*?*/
"" == 0; /*?*/
"" === "0"; /*?*/
"" === 0; /*?*/References · 2 min
// References
let x = 10;
let y = x;
x; /*?*/
y; /*?*/
y = 2;
x; /*?*/
let obj = {};
let refObj = obj;
obj.id = 123;
console.log(refObj.id);
let data = {};
let ref = data;
let moreData = {};
data === ref; /*?*/
data === moreData; /*?*/null vs undefined · 3 min
// Null vs undefined
null == undefined; /*?*/
let somevar; // undefined
somevar != null; /*?*/
// root level undefined
typeof globalVar !== 'undefined'; /*?*/this · 4 min
// this
function sayYo() { return `Yo! ${this}` }
sayYo(); /*?*/
const myObj = { welcome: sayYo };
myObj.welcome(); /*?*/closure · 5 min
// closure
function outer() {
const outsideScopeVar = 'out of the box';
function inner() { return outsideScopeVar; }
return inner;
}
const getInner = outer();
getInner(); /*?*/truthy falsy values · 6 min
// truthy & falsy values
if (1) {
console.log('ok! 😁');
}
if (0) {
console.log('not ok! 🙁');
}
// bang bang
!!''; /*?*/
!!0; /*?*/
!!NaN; /*?*/
!!null; /*?*/
!!undefined; /*?*/
!!{}; /*?*/
!![]; /*?*/