As presented at DevDuck #1 - JavaScript meetup for developers (www.devduck.pl)
Prezentacja z #1 spotkania DevDuck'a w Gliwicach (www.devduck.pl), spotkania mającego na celu poszerzanie wiedzy i wymianę doświadczeń z zakresu szeroko pojętego JS'a, a w szczególności Node.js/React.js i im pochodnych kończących się na ".js" :).
----
Spotkanie odbyło się w Gliwicach w siedzibie Brainhub (www.brainhub.eu)
4. Lexical scope
● Zasięg zmiennych jest określany na podstawie ich umiejscowienia w kodzie i kontekstu
w jakim się znajdują
● Scope zmiennych jest stały, określany na etapie kompilacji (wczesne wiązanie)
● W JavaScripcie scope jest określany poprzez funkcje (ES5) oraz bloki kodu (ES6)
5. Lexical scope
● Kod wewnątrz scope'a ma dostęp do zmiennych zadeklarowanych w scopie
zewnętrznym
● W pierwszej kolejności wykorzystywane są zmienne w lokalnym zasięgu, następnie
kolejne poziomy zagnieżdzenia scope'a
const a = 1;
const b = 2;
function x() {
const b = 3;
console.log(a); // => 1
console.log(b); // => 3
}
6. Function scope
● Jedyny dostępny sposób określania zasięgu zmiennych w ES5
● Najmniejszą jednostką scope'a jest funkcja
● Mechanizm specyficzny dla JavaScriptu
● Do deklaracji zmiennej wewnątrz scope'a służy słowo kluczowe var
● Użycie var w ES6+ jest niezalecane
7. Czym jest hoisting?
● Dwie fazy przetwarzania kodu - kompilacja i wykonanie
var a = 1;
var myFunction = function () {
// code...
};
function myOtherFunction() {
// code...
}
myFunction();
myOtherFunction();
8. Czym jest hoisting?
● W fazie kompilacji wczytywane są
jedynie deklaracje (zarówno
zmiennych jak i funkcji)
var a;
var myFunction;
function myOtherFunction() {
// code...
}
a = 1;
myFunction = function () {
// code...
};
myFunction();
myOtherFunction();
● W fazie wykonywania kodu
przetwarzane są pozostałe instrukcje -
przypisania zmiennych, wywołania
funkcji itp
9. Hoisting - minusy
● Hoisting deklaracji zmiennych może prowadzić do nieczytelnego, nieoczywistego kodu
var a = 1;
function doSomeStuff() {
a = 2;
var a = 3;
return a;
}
console.log(doSomeStuff()); // => 3
console.log(a); // => 1
10. Hoisting - plusy
● Hoisting funkcji pozwala na czytelniejszy zapis kodu - funkcje zawierające główną
logikę można umieścić przed funkcjami pomocniczymi
function doSomeStuff() {
runHelper();
// other code...
}
function runHelper() {
// code...
}
11. var
● Ze względu na hoisting wszystkie deklaracje powinny znajdować się na początku
funkcji
● Możliwa ponowna deklaracja zmiennej
function doSomeStuff() {
// all declarations with optional assigments:
var a;
var b = 'something';
var c = 'something';
// rest of the code...
}
12. Block scope
● Sposób określania zasięgu zmiennych dostępny od ES6
● Najmniejszą jednostką scope'a jest blok kodu reprezentowany przez nawiasy
klamrowe
● Mechanizm znany z wiekszości języków programowania
● Do deklaracji zmiennej wewnątrz block scope'a służą słowa kluczowe let oraz const
13. let & const
● Brak możliwości ponownej deklaracji zmiennej
● Dodatkowo const nie pozwala na ponowne przypisanie wartości do
zmiennej (nie mylić z modyfikacją typów złożonych)
● Deklaracje zmiennych powinny znajdować się jak najbliżej ich
wykorzystania
14. Kiedy var, let a kiedy const?
● Zasada: zawsze preferuj niemutowalny kod
● Dlaczego? Kod jest łatwiejszy w zrozumieniu i debugowaniu
● W ES6+ var nie powinno być nigdy stosowane
● const powinien stanowić domyślny wybór
● let powinien być stosowany tylko wtedy, gdy wartość zmiennej jest ponownie
przypisywana (np. licznik pętli)
18. Symulowanie bock scope'a w ES5
● Do symulowania block scope'a służy IIFE ( immediately-invoked function expression )
function changeRestStyle() {
var mainColor = '#FF0000';
(function () {
var header = document.getElementById('header');
var accentColor = '#928c00';
header.style.backgroundColor = mainColor;
header.style.color = accentColor;
}());
(function () {
var footer = document.getElementById('footer');
footer.style.backgroundColor = mainColor;
})();
}
19. First-class functions
● Funkcje w JavaScript są obiektami pierwszej kategorii - mogą być traktowane jak
wartości i przypisywane do zmiennych oraz stanowić elementy tablic i pola obiektów,
● Funkcje mogą być przekazywane jako argumenty do innych funkcji, mogą także
stanowić wartość zwracaną z funkcji
● Funkcje, które przyjmuja inną funkcje jako argument lub zwracają inną funkcję są
nazywane funkcjami wyższego rzedu (higher order functions)
● Funkcje mogą byc dowolnie zagnieżdżane, każda funkcja tworzy nowy scope
20. Czym jest domknięcie (closure)?
● Domknięcie to zapis w pamięci silnika, przechowujący funkcję wraz z jej środowiskiem
● Środowisko funkcji stanowią wszystkie zmienne zadeklarowane w scope otaczającym
funkcję, które zostały wewnątrz niej użyte
● Funkcja ma dostęp do swojego lexical scope’a nawet jeśli jest wywoływana poza
swoim scopem
● Domknięcie jest tworzone w miejscu deklaracji funkcji
21. Podstawowy przykład domknięcia
const name = 'Maciek';
function greet() {
return `Hello, my name is ${name}.`;
}
const result = greet(); // => "Hello, my name is Maciek."
22. Prosta funkcja wyższego rzędu
function createGreet() {
const name = 'Maciek';
return function() {
return `Hello, my name is ${name}.`;
};
}
const greet = createGreet();
const result = greet(); // => "Hello, my name is Maciek."
23. Factory function
function createPerson(name) {
const species = 'Homo Sapiens';
return {
showDescription() {
return `Person is a ${species} named ${name}.`;
},
};
}
const john = createPerson('John');
john.showDescription(); // => "Person is a Homo Sapiens named John."
24. Module pattern (ES5)
var calculator = function () {
function add(a, b) {
return a + b;
}
function square(a) {
return a * a;
}
function sumOfSquares(a, b) {
return add(aquare(a), square(b));
}
return {
sumOfSquares: sumOfSquares,
};
}();
27. Podsumowanie
● Twórz prosty, modularny, wolny od “magii” kod
● Ograniczaj ruchome części w kodzie, używaj const gdzie to tylko możliwe
● Ograniczaj zakres widoczności zmiennych, organizuj kod w precyzyjne scope'y
● Ukrywaj detale implementacyjne - jedną z metod jest użycie domknięć
● Twórz łatwy w ponownym wykorzystaniu, deklaratywny kod - wykorzystuj zalety funkcji
wyższego rzędu i domknięć