Język programowania JavaScript · 2020. 4. 6. · – Wszystkie słowa kluczowe języka Java były...

77
Język programowania JavaScript dr hab. inż. Marek Wojciechowski

Transcript of Język programowania JavaScript · 2020. 4. 6. · – Wszystkie słowa kluczowe języka Java były...

Page 1: Język programowania JavaScript · 2020. 4. 6. · – Wszystkie słowa kluczowe języka Java były zastrzeżone w pierwszej wersji JavaScript • Najważniejsze różnice między

Język programowania JavaScript

dr hab. inż. Marek Wojciechowski

Page 2: Język programowania JavaScript · 2020. 4. 6. · – Wszystkie słowa kluczowe języka Java były zastrzeżone w pierwszej wersji JavaScript • Najważniejsze różnice między

2

Historia języka JavaScript

• Opracowany przez firmę Netscape w 1995 roku

– Brendan Eich strorzył JavaScript w 10 dni

– Język skryptowy dla przeglądarki Netscape Navigator jako prostsza alternatywa i uzupełnienie dla apletów Java (Robocze nazwy: Mocha, LiveScript)

– Serwerowa implementacja JavaScript dla Netscape Enterprise Server udostępniona krótko po wersji dla przeglądarki

• W 1996 Microsoft udostępnia JScript jako port JavaScript

• Standaryzacja języka pod nazwą ECMAScript (ECMA-262)

• JavaScript, JScript, ActionScript jako implementacje ECMAScript

Page 3: Język programowania JavaScript · 2020. 4. 6. · – Wszystkie słowa kluczowe języka Java były zastrzeżone w pierwszej wersji JavaScript • Najważniejsze różnice między

3

Historia wersji ECMAScript

• 1997 – 1st Edition, 1998 – 2nd Edition (zmiany edycyjne)

• 1999 – 3rd Edition (try/catch, wyrażenia regularne, …)

• 4th Edition – zarzucona (złożoność języka, względy polityczne)

• 2009 – 5th Edition (strict mode, wsparcie JSON)

• ES 2015/6 (klasy, moduły, funkcje strzałkowe, nowe operatory, …)

• ES 2016/7 (**), ES 2017/8 (async/await), ES 2018/9 (drobne uzupełnienia)

Page 4: Język programowania JavaScript · 2020. 4. 6. · – Wszystkie słowa kluczowe języka Java były zastrzeżone w pierwszej wersji JavaScript • Najważniejsze różnice między

4

Cechy języka JavaScript

• Łączy programowanie strukturalne, obiektowe i funkcyjne

• Język skryptowy, interpretowany – Uruchamiany w maszynach wirtualnych nazywanych silnikami JavaScript

– Silniki JavaScript dostępne w przeglądarkach internetowych, ale nie tylko

– Kompilacja just-in-time w niektórych przeglądarkach

• Język dynamiczny – Dynamiczne typowanie (typ związany z wartością, a nie zmienną)

– Dynamiczna zmiana zestawu właściwości i funkcjonalności obiektów

– Definiowanie funkcji w trakcie pracy programu

– Możliwość wykonania kodu dostarczonego jako łańcuch znaków

• Funkcja eval()

• Programowanie obiektowe oparte na prototypach

– Zamiast dziedziczenia opartego na klasach

Page 5: Język programowania JavaScript · 2020. 4. 6. · – Wszystkie słowa kluczowe języka Java były zastrzeżone w pierwszej wersji JavaScript • Najważniejsze różnice między

5

Zastosowania JavaScript

• Przeglądarki WWW (frontend)

– Jedna z 3 podstawowych technologii do tworzenia zawartości stron WWW (obok HTML i CSS)

– Dynamiczne generowanie zawartości po stronie przeglądarki

• Rozwiązania serwerowe dla aplikacji WWW (backend)

– Node.js

• Bazy danych NoSQL

– JSON jako format danych, JavaScript do zapytań i przetwarzania danych (MongoDB, CouchDB)

• Inne zastosowania jako wbudowany język skryptowy

– Rozszerzenia przeglądarek, Adobe Acrobat i Reader, Open Office, …

• Język pośredni dla transkompilatorów nowych języków

– TypeScript, CoffeeScript, Dart, …

Page 6: Język programowania JavaScript · 2020. 4. 6. · – Wszystkie słowa kluczowe języka Java były zastrzeżone w pierwszej wersji JavaScript • Najważniejsze różnice między

6

Zastosowania JS na stronach WWW

• Dawniej: Dynamic HTML (DHTML)

– Logika programowa dodana do HTML-a

– Skrypty dokonują interakcji z obiektowym modelem dokumentu (Document Object Model (DOM)), modyfikacje strony w przeglądarce poprzez interfejs DOM

– Przykłady zastosowań:

• Animacje, gry, odtwarzanie multimediów

• Walidacja danych wprowadzanych do formularzy

• Otwieranie dodatkowych okien

• Obecnie: Frontend development

– Rozwinięcie DHTML

– Logika prezentacji w JavaScript po stronie przeglądarki

– Logika biznesowa w dowolnej technologii po stronie serwera

– Żądania HTTP z poziomu JavaScript wywołujące logikę biznesową (Ajax)

Page 7: Język programowania JavaScript · 2020. 4. 6. · – Wszystkie słowa kluczowe języka Java były zastrzeżone w pierwszej wersji JavaScript • Najważniejsze różnice między

7

JavaScript a Java

• „Java is to Javascript as car is to carpet”

• Podobieństwa i związki:

– Składnia obu języków wywodzi się ze składni języka C

– Standardowa biblioteka JavaScriptu zachowuje konwencje Javy

– Obiekty Math i Date w JavaScript oparte na Math i Date z Java 1.0

– Wszystkie słowa kluczowe języka Java były zastrzeżone w pierwszej wersji JavaScript

• Najważniejsze różnice między JavaScript i Java:

Cecha JavaScript Java

Typowanie Dynamiczne Statyczne

Kompilacja Brak Do bajtkodu

Obiektowość Prototypy Klasy

Programowanie funkcyjne Od początku Lambdy od Java 8

Składnia Specyficzne operatory i instrukcje sterujące

Page 8: Język programowania JavaScript · 2020. 4. 6. · – Wszystkie słowa kluczowe języka Java były zastrzeżone w pierwszej wersji JavaScript • Najważniejsze różnice między

8

Typy danych w JavaScript

• Typy proste

– Liczba (number) – 64-bity, zmiennoprzecinkowe (IEEE 754 standard)

• np. 2, -3, 3.14, 2.9e8, 0xFF, 0b1011, 0o67, Infinity, -Infinity, NaN

– Łańcuchy znaków (string) – niemodyfikowalne

• ograniczniki: " ", ' ', ``; znaki specjalne: \n, \t, \\, \', \""

• np. 'Test stringa\n', "Drugi 'string'."

– Wartości logiczne (boolean): true, false

• Struktury danych

– Tablice, np. [3, 5, -3] (tablice są obiektami)

– Obiekty, np. { marka: 'Opel', nrRej: 'PO65947' };

• Specjalne wartości

– null (typu object, przez pomyłkę…) – brak wartości, brak obiektu

– undefined (typu undefined) – wartość zadeklarowanej, ale nie zainicjalizowanej zmiennej lub właściwości obiektu

– symbole

Page 9: Język programowania JavaScript · 2020. 4. 6. · – Wszystkie słowa kluczowe języka Java były zastrzeżone w pierwszej wersji JavaScript • Najważniejsze różnice między

9

Operatory w JavaScript

• ., [], ()

• Arytmetyczne: +, -, *, /, %, ++, --, ** (ES7)

• Konkatenacja łańcuchów znaków: +, +=

• Bitowe: &, |, ^, ~, <<, >>, >>>

• Przypisania: =, +=, -=, …, <<=, …, &=, …

• Porównania: ==, !=, ===, !==, >, >=, <, <=

• Logiczne: &&, ||, ! (skrócone wartościowanie && i ||)

• new, delete, typeof, void, in, instanceof

• Operator przecinka: ,

• Operator warunkowy (ternarny): ?:

• Destrukturyzacja tablicy/obiektu (ES6)

• Operatory rest i spread: … (ES6)

Page 10: Język programowania JavaScript · 2020. 4. 6. · – Wszystkie słowa kluczowe języka Java były zastrzeżone w pierwszej wersji JavaScript • Najważniejsze różnice między

10

Automatyczna konwersja typów

console.log(5 * null) // 0

console.log(null * 5) // 0

console.log("6" - 1) // 5

console.log(6 - "1") // 5

console.log("6" + 1) //61

console.log(6 + "1") // 61

console.log("three" * 2) // NaN

console.log(2 * "three") // NaN

console.log(3 + null); // 3

console.log(3 + undefined); // NaN

console.log(3 + false); // 3

console.log(true + true); // 2

Page 11: Język programowania JavaScript · 2020. 4. 6. · – Wszystkie słowa kluczowe języka Java były zastrzeżone w pierwszej wersji JavaScript • Najważniejsze różnice między

11

Operatory ==/!= i ===/!==

• ===/!== testują precyzyjną równość

– Oprócz wartości uwzględniają typ danych

console.log(false == 0); // true

console.log(false === 0); // false

console.log(null == undefined); // true

console.log(null === undefined); // false

console.log(null == 0); // false

console.log(null === 0); // false

console.log(false != 0); // false

console.log(false !== 0); // true

console.log(null != undefined); // false

console.log(null !== undefined); // true

console.log(null != 0); // true

console.log(null !== 0); // true

Page 12: Język programowania JavaScript · 2020. 4. 6. · – Wszystkie słowa kluczowe języka Java były zastrzeżone w pierwszej wersji JavaScript • Najważniejsze różnice między

12

Pułapki porównań przez ==

• Elastyczność języka JavaScript w zakresie konwersji typów sprawia, że wyniki porównań operatorem == mogą nie być oczywiste

console.log(0 == '0'); // true

console.log(0 == ''); // true

console.log('' == '0'); // ... false!

console.log(false == undefined); // false

console.log(false == null); // false

console.log(null == undefined); // ... true!

Page 13: Język programowania JavaScript · 2020. 4. 6. · – Wszystkie słowa kluczowe języka Java były zastrzeżone w pierwszej wersji JavaScript • Najważniejsze różnice między

13

Zmienne i stałe

• Zmienne nie posiadają typu (typ mają przypisane wartości)

• Nazwa zmiennej musi być poprawnym identyfikatorem

• Deklaracja zmiennej:

– var – zasięg funkcji

– let – zasięg bloku kodu (ES6)

• Odwołanie do niezadeklarowanej zmiennej powoduje jej poszukiwanie „w górę zasięgów” aż do globalnego obiektu (w przeglądarkach: window)

– Zabronione w trybie strict ("use strict";)

– Odczyt niezainicjalizowanej niezadeklarowanej zmiennej kończy się błędem (dla zadeklarowanej zwraca undefined)

• Deklaracja stałej:

– const (ES6)

Page 14: Język programowania JavaScript · 2020. 4. 6. · – Wszystkie słowa kluczowe języka Java były zastrzeżone w pierwszej wersji JavaScript • Najważniejsze różnice między

14

Zmienne i stałe - Przykłady

var nazwisko = "Kowalski";

var imie = 'Jan';

var _$_dziwna__zmienna_99 = 0xabcd;

var flaga = true;

var innaFlaga = (5 > 7);

var mojeAuto = { marka: 'Fiat', nrRej: 'PNC2781' };

var tablica = [4, 7, 9];

const pi = 3.14;

Page 15: Język programowania JavaScript · 2020. 4. 6. · – Wszystkie słowa kluczowe języka Java były zastrzeżone w pierwszej wersji JavaScript • Najważniejsze różnice między

15

Tablice

• Obsługa tablic za pomocą obiektu Array

– Nie jest konieczne jawne korzystanie z niego

– Możliwość utworzenia i inicjalizacji tablicy konstrukcją []

• Indeksowane od 0 (tylko indeksy liczbowe!)

• Składowa length

• Użyteczne metody (zdefiniowane w prototypie), np. push, pop, sort, forEach, …

• Rzadka indeksacja tablic („dziury w numeracji komórek”)

• Dostęp do elementów tablicy operatorem []

Page 16: Język programowania JavaScript · 2020. 4. 6. · – Wszystkie słowa kluczowe języka Java były zastrzeżone w pierwszej wersji JavaScript • Najważniejsze różnice między

16

Tablice - Przykłady

var miasta = new Array('Berlin','Londyn','Nowy Jork');

var kraje = ['Niemcy','Wielka Brytania','USA'];

var kontynenty = new Array(2);

kontynenty[0] = 'Europa';

kontynenty[1] = 'Ameryka Północna';

console.log(kontynenty.length); // 2

kontynenty[3] = "Afryka"; // 4

console.log(kontynenty.length);

kontynenty.push("Azja");

console.log(kontynenty.length); // 5

console.log(kontynenty);

// ["Europa", "Ameryka Północna", 3: "Afryka", 4: "Azja"]

Page 17: Język programowania JavaScript · 2020. 4. 6. · – Wszystkie słowa kluczowe języka Java były zastrzeżone w pierwszej wersji JavaScript • Najważniejsze różnice między

17

Instrukcje sterujące

• Warunkowe: if, if/else, switch

• Pętle: while, do/while, for, for … in, for … of (ES6)

• Instrukcje używane w pętlach: break, continue

• Obsługa wyjątków: try/catch/finally

Page 18: Język programowania JavaScript · 2020. 4. 6. · – Wszystkie słowa kluczowe języka Java były zastrzeżone w pierwszej wersji JavaScript • Najważniejsze różnice między

18

Pętle for … in i for … of

let car = { marka: "Fiat", cena: 27000};

for (let i in car) {

console.log(i); // "marka", "cena"

}

// for (let i of car) {} // error!

for (let i in car) {

console.log(car[i]); // "Fiat", 27000

}

• for … in iteruje po właściwościach obiektu

– Uwaga: tablice też są obiektami

• for … of iteruje po wartościach właściwości obiektów iterowalnych (tablice, mapy, …)

Page 19: Język programowania JavaScript · 2020. 4. 6. · – Wszystkie słowa kluczowe języka Java były zastrzeżone w pierwszej wersji JavaScript • Najważniejsze różnice między

19

Pętle for … in i for … of (c.d.)

let arr = [3, 5, 7];

for (let i in arr) {

console.log(i); // 0, 1, 2

}

for (let i of arr) {

console.log(i); // 3, 5, 7

}

for (let i in arr) {

console.log(arr[i]); // 3, 5, 7

}

Page 20: Język programowania JavaScript · 2020. 4. 6. · – Wszystkie słowa kluczowe języka Java były zastrzeżone w pierwszej wersji JavaScript • Najważniejsze różnice między

20

Funkcje

• Blok kodu, który wykonuje się gdy zostanie wywołany

– Typowo nazwany blok programu

– Funkcja może być utworzona jako anonimowa

• Funkcja może przyjmować parametry

– Przy wywołaniu można przekazać mniejszą lub większą liczbę parametrów niż zadeklarowano

• Nieustawione zadeklarowane parametry są undefined

• Dostęp do wszystkich parametrów poprzez obiekt arguments

• Funkcja może zwracać wartość (instrukcja return opcjonalna)

• Funkcje same są obiektami (!) – mają pola i metody

• Funkcję można przypisać do zmiennej lub składowej obiektu

• Funkcję można przekazać jako argument funkcji

• Funkcja może zwracać funkcję jako wynik

• Konstruktor - funkcja o specjalnym zastosowaniu (new)

Page 21: Język programowania JavaScript · 2020. 4. 6. · – Wszystkie słowa kluczowe języka Java były zastrzeżone w pierwszej wersji JavaScript • Najważniejsze różnice między

21

Zasięg zmiennych: funkcji i bloku

function testVar() {

var x = 5;

if (x == 5) {

var x = 8; // ta sama zmienna o zasięgu funkcji

console.log(x); // 8

}

console.log(x); // 8

}

function testLet() {

let x = 5;

if (x == 5) {

let x = 8; // nowa zmienna, lokalna dla bloku kodu

console.log(x); // 8

}

console.log(x); // 5

}

Page 22: Język programowania JavaScript · 2020. 4. 6. · – Wszystkie słowa kluczowe języka Java były zastrzeżone w pierwszej wersji JavaScript • Najważniejsze różnice między

22

Programowanie funkcyjne

var t = [3, 8, 9];

t.forEach(function(element) {

console.log(element);

})

var showElements = function(element) {

console.log(element);

};

t.forEach(showElements);

function showElementDetails(element, index, array) {

console.log('a[' + index + '] = ' + element);

}

[2, 25, , 19].forEach(showElementDetails);

Page 23: Język programowania JavaScript · 2020. 4. 6. · – Wszystkie słowa kluczowe języka Java były zastrzeżone w pierwszej wersji JavaScript • Najważniejsze różnice między

23

Programowanie funkcyjne (c.d.)

var numbers = [3, 8, 9];

var squares = numbers.map(function(x) {

return(x*x) ;

})

console.log(squares); // [9, 64, 81]

var numbers = [3, 8, 9];

var squares = numbers.map((x) => {return x*x; } )

console.log(squares); // [9, 64, 81]

var numbers = [3, 8, 9];

var squares = numbers.map( x => x*x )

console.log(squares); // [9, 64, 81]

Funkcje strzałkowe (ES6)

Page 24: Język programowania JavaScript · 2020. 4. 6. · – Wszystkie słowa kluczowe języka Java były zastrzeżone w pierwszej wersji JavaScript • Najważniejsze różnice między

24

Problem: Przechowanie stanu między wywołaniami funkcji z jednoczesnym ograniczeniem dostępu do tego stanu

var counter = 0;

function count() {

counter += 1;

}

count();

count();

// 2

• Zmienna globalna?

– Możliwy dostęp z zewnątrz

• Zmienna lokalna w funkcji?

– Odrębne instancje w kolejnych wywołaniach funkcji

function count() {

var counter = 0;

counter += 1;

}

count();

count();

// ???

* Przykład z w3schools.com

Page 25: Język programowania JavaScript · 2020. 4. 6. · – Wszystkie słowa kluczowe języka Java były zastrzeżone w pierwszej wersji JavaScript • Najważniejsze różnice między

25

Domknięcie (ang. closure)

var count = (function () {

var counter = 0;

return function () {return counter += 1;}

})();

count();

count();

// 2

• Zagnieżdżona funkcja, która ma dostęp do lokalnych zmiennych funkcji nadrzędnej

– Również po zakończeniu działania funkcji nadrzędnej!

– Środowisko przechowuje nielokalne obiekty używane przez funkcję

* Przykład z w3schools.com

Page 26: Język programowania JavaScript · 2020. 4. 6. · – Wszystkie słowa kluczowe języka Java były zastrzeżone w pierwszej wersji JavaScript • Najważniejsze różnice między

26

Operatory rest i spread

• Ten sam zapis (…), ale „odwrotne” działanie

• Rest – łączy parametry funkcji w tablicę

• Spread – rozbija tablicę na listę argumentów funkcji

function add(n1, n2) {

return n1 + n2;

}

var tab = [3, 7];

var result = add(...tab);

console.log(result); // 10

function add(...numbers) {

return numbers.reduce((sum, elem) => sum + elem);

}

var result = add(3, 5, 8);

console.log(result); // 16

Page 27: Język programowania JavaScript · 2020. 4. 6. · – Wszystkie słowa kluczowe języka Java były zastrzeżone w pierwszej wersji JavaScript • Najważniejsze różnice między

27

Obiekty w JavaScript

var person = {firstName: "Marek", lastName: "Wojciechowski",

hello: function() {console.log('Hi!');}};

console.log(typeof(person)); // object

person.hello();

console.log(person.firstName);

console.log(person['firstName']);

person.age = 43;

person.bye = function() {console.log('Bye!');};

person.bye();

console.log(person.age);

delete person.firstName;

console.log(person.firstName); // undefined

• Obiekt = kolekcja dowolnych właściwości

– Właściwości mogą być dodawane i usuwane w czasie życia obiektu

– Właściwości mogą być funkcjami = metody obiektu

Page 28: Język programowania JavaScript · 2020. 4. 6. · – Wszystkie słowa kluczowe języka Java były zastrzeżone w pierwszej wersji JavaScript • Najważniejsze różnice między

28

Operatory destrukturyzacji

• Dla tablic:

[v1, v2, …] = tab

• Dla obiektów:

{p1: v1, p2: v2, …} = obj

• Zamiana wartości zmiennych z użyciem destrukturyzacji

let x = 5;

let y = 7;

[x, y] = [y, x];

console.log(x); // 7

console.log(y); // 5

Page 29: Język programowania JavaScript · 2020. 4. 6. · – Wszystkie słowa kluczowe języka Java były zastrzeżone w pierwszej wersji JavaScript • Najważniejsze różnice między

29

Obiekty jako mapy

var person = {firstName: "Marek", lastName: "Wojciechowski"};

for (var p in person) // firstName, lastName

console.log(p);

person["age"] = 43;

delete person.firstName;

for (var q in person) // lastName, age

console.log(q);

console.log("firstName" in person); // false

console.log("lastName" in person); // true

console.log(Object.keys(person)); // ["lastName", "age"]

• Obiekty mogą być używane jako mapy (tablice asocjacyjne)

– Operator in umożliwia sprawdzenie czy właściwość jest zdefiniowana w obiekcie

– Pętla for … in iteruje po właściwościach

– Object.keys zwraca tablicę kluczy

Page 30: Język programowania JavaScript · 2020. 4. 6. · – Wszystkie słowa kluczowe języka Java były zastrzeżone w pierwszej wersji JavaScript • Najważniejsze różnice między

30

Gettery i settery w JavaScript

var person = {

firstName: 'Marek',

lastName: 'Wojciechowski',

get fullName() {

return this.firstName + ' ' + this.lastName;

},

set fullName (fName) {

var names = fName.toString().split(' ');

this.firstName = names[0] || '';

this.lastName = names[1] || '';

}

}

console.log(person.fullName) // Marek Wojciechowski

person.fullName = 'Jan Kowalski';

console.log(person.firstName); // Jan

console.log(person.lastName) // Kowalski

Page 31: Język programowania JavaScript · 2020. 4. 6. · – Wszystkie słowa kluczowe języka Java były zastrzeżone w pierwszej wersji JavaScript • Najważniejsze różnice między

31

Enumerowalne i nie-enumerowalne właściwości

var person = {firstName: "Marek"};

person.lastName = "Wojciechowski";

person["age"] = 43;

person.sayHi = function () { console.log("Hi!"); };

for (var q in person) // firstName, lastName, age, sayHi

console.log(q);

• Właściwości definiowane w obiektach poprzez przypisanie są enumerowalne

– Widoczne w pętli for … in

– Zwracane przez Object.keys()

• Możliwe jest definiowanie właściwości nie-enumerowalnych za pomocą Object.defineProperty()

Page 32: Język programowania JavaScript · 2020. 4. 6. · – Wszystkie słowa kluczowe języka Java były zastrzeżone w pierwszej wersji JavaScript • Najważniejsze różnice między

32

Object.defineProperty()

var person = {firstName: "Marek", lastName: "Wojciechowski"};

Object.defineProperty(person, "age",

{enumerable: false, writable: true, value: 43});

for (var q in person) // firstName, lastName

console.log(q);

console.log(Object.keys(person)); // ["firstName", "lastName"]

console.log(person.age); // 43

person.age=44;

console.log(person.age); // 44

• Definiuje lub modyfikuje właściwość obiektu

• Składnia: Object.defineProperty(obj, property, descriptor)

• Atrybuty deskryptora:

– Dla danych (w tym funkcji) i akcesorów: configurable, enumerable

– Dla danych (w tym funkcji): value, writable

– Dla akcesorów: get, set

Page 33: Język programowania JavaScript · 2020. 4. 6. · – Wszystkie słowa kluczowe języka Java były zastrzeżone w pierwszej wersji JavaScript • Najważniejsze różnice między

33

Prywatny stan obiektu

var counterObj = (function () {

var counter = 0;

return {

inc: function () {counter += 1;},

value: function () { return counter; }

}

})();

console.log(counterObj.value()); // 0

counterObj.inc();

counterObj.inc();

console.log(counterObj.value()); // 2

• JavaScript nie oferuje kwalifikatorów dostępu do składowych obiektu

• Składowe obiektu są dostępne z zewnątrz

• Efekt „prywatnych pól” można uzyskać poprzez domknięcie

Page 34: Język programowania JavaScript · 2020. 4. 6. · – Wszystkie słowa kluczowe języka Java były zastrzeżone w pierwszej wersji JavaScript • Najważniejsze różnice między

34

Konstruktory

function Rabbit(type) {

this.type = type;

}

var killerRabbit = new Rabbit("killer");

var blackRabbit = new Rabbit("black");

console.log(blackRabbit.type);

// black

• Funkcje wykorzystywane do tworzenia obiektów

– Wywoływane poprzez operator new

– Umożliwiają programową inicjalizację obiektu

– Niejawnie zwracają nowo tworzony obiekt

– Mają dostęp do zmiennej this wskazującej na bieżący obiekt

– Zapewniają jednolitą strukturę i funkcjonalność obiektów danego rodzaju (w momencie ich utworzenia)

Page 35: Język programowania JavaScript · 2020. 4. 6. · – Wszystkie słowa kluczowe języka Java były zastrzeżone w pierwszej wersji JavaScript • Najważniejsze różnice między

35

Metody obiektów

function Rabbit(type) {

this.type = type;

this.speak = function(line) {

console.log("The " + this.type + " rabbit says '" +

line + "'");

};

}

• Metody można dodawać dynamicznie do obiektów

– Obiekty utworzone tym samym konstruktorem mogą później różnić się funkcjonalnością

• Jak zapewnić na starcie ten sam zestaw metod obiektom danego rodzaju?

– Można dodać metody w ciele konstruktora

• Obiekty będą miały własny zestaw tych samych metod

– Lepszym rozwiązaniem jest wykorzystanie prototypu

• Zestaw metod w prototypie współdzielony przez obiekty na nim oparte

Page 36: Język programowania JavaScript · 2020. 4. 6. · – Wszystkie słowa kluczowe języka Java były zastrzeżone w pierwszej wersji JavaScript • Najważniejsze różnice między

36

Prototypy

• Prototyp (ang. prototype) to w JavaScript to obiekt który dla danego obiektu stanowi „zapasowe” źródło właściwości

• Prototypem większości obiektów w JS jest Object.prototype

– Dostarcza kilka metod np. toString(), valueOf()

– Jego właściwości są nie-enumerowalne

• Prototypy tworzą drzewiastą hierarchię

– Odpowiednik hierarchii dziedziczenia klas

• Odczyt prototypu: Object.getPrototypeOf()

• Tworzenie obiektu z prototypu: Object.create(prototyp);

• Zmiana prototypu (ES6): Object.setPrototypeOf()

– Operacja czasochłonna, niezalecana

• Rozróżnienie własnych i odziedziczonych właściwości:

– hasOwnProperty(), Object.getOwnPropertyNames(), Object.getOwnPropertyDescriptor()

Page 37: Język programowania JavaScript · 2020. 4. 6. · – Wszystkie słowa kluczowe języka Java były zastrzeżone w pierwszej wersji JavaScript • Najważniejsze różnice między

37

Konstruktory i prototypy

function Rabbit(type) {

this.type = type;

}

Rabbit.prototype.speak = function(line) {

console.log("The " + this.type + " rabbit says '" +

line + "'");

};

var blackRabbit = new Rabbit("black");

blackRabbit.speak("Hi!!!");

• Konstruktory (jak inne funkcje) posiadają właściwość prototype

– Umożliwia ona przypisanie zestawu metod, które mają być dostępne dla obiektów tworzonych danym konstruktorem

– Uwaga: NIE jest to prototyp funkcji jako obiektu (prototypem funkcji jest domyślnie Function.prototype)

Page 38: Język programowania JavaScript · 2020. 4. 6. · – Wszystkie słowa kluczowe języka Java były zastrzeżone w pierwszej wersji JavaScript • Najważniejsze różnice między

38

this

function testThis() {

return this;

}

console.log(testThis());

// window

• W kontekście globalnym (poza funkcjami) this wskazuje globalny obiekt (w przeglądarce: window)

• W kontekście funkcji, jeśli funkcja nie została wywołana na rzecz konkretnego obiektu, to wartość this zależy od włączenia trybu strict (obiekt globalny lub undefined)

• W kontekście funkcji, jeśli funkcja została wywołana na rzecz konkretnego obiektu, to this wskazuje na ten obiekt

function testThis() {

"use strict";

return this;

}

console.log(testThis());

// undefined

Page 39: Język programowania JavaScript · 2020. 4. 6. · – Wszystkie słowa kluczowe języka Java były zastrzeżone w pierwszej wersji JavaScript • Najważniejsze różnice między

39

this – sposoby wywołania funkcji na rzecz obiektu

• Wywołanie funkcji jako metody obiektu (notacja .)

• Wywołanie przez Function.prototype.call

• Wywołanie przez Function.prototype.apply

• Wywołanie funkcji dowiązanej (Bound Function), utworzonej przez Function.prototype.bind

Page 40: Język programowania JavaScript · 2020. 4. 6. · – Wszystkie słowa kluczowe języka Java były zastrzeżone w pierwszej wersji JavaScript • Najważniejsze różnice między

40

this – Przykłady (pożyczanie metod)

var john = { fname: "John",

greet: function () {

console.log("Hi! I'm " + this.fname);

}

};

john.greet(); // Hi! I'm John

var jane = { fname: "Jane" };

jane.greet = john.greet;

jane.greet(); // Hi! I'm Jane

var greet = john.greet;

greet(); // Hi! I'm undefined

• Metodę obiektu można wywołać na rzecz innego obiektu

– this jest ustawiane w momencie wywołania

Page 41: Język programowania JavaScript · 2020. 4. 6. · – Wszystkie słowa kluczowe języka Java były zastrzeżone w pierwszej wersji JavaScript • Najważniejsze różnice między

41

Jawne ustawienie this przy wywołaniu funkcji

...

var greet = john.greet;

greet(); // Hi! I'm undefined

greet.call(john); // Hi! I'm John

greet.apply(jane, []); // Hi! I'm Jane

• Function.prototype.call

– Pierwszy argument ustawia this

– Argumenty dla funkcji przekazane jako kolejne argumenty call(), oddzielane przecinkami

• Function.prototype.apply

– Pierwszy argument ustawia this

– Argumenty dla funkcji przekazane jako drugi argument apply(), w formie tablicy

Page 42: Język programowania JavaScript · 2020. 4. 6. · – Wszystkie słowa kluczowe języka Java były zastrzeżone w pierwszej wersji JavaScript • Najważniejsze różnice między

42

Funkcje dowiązane

var jane = { fname: "Jane" };

var greet = function () {

console.log("Hi! I'm " + this.fname);

}

greet(); // Hi! I'm undefined

var boundGreet = greet.bind(jane);

boundGreet(); // Hi! I'm Jane

• Tworzone za pomocą Function.prototype.bind

• Funkcja dowiązana pośredniczy w wywołaniu funkcji docelowej

– Ustawia jej this na obiekt wskazany przy tworzeniu funkcji dowiązanej (pierwszym argumentem bind())

– Opcjonalnie dodaje na początku listy argumentów funkcji docelowej argumenty podane przy tworzeniu funkcji dowiązanej (2-gi i kolejne)

Page 43: Język programowania JavaScript · 2020. 4. 6. · – Wszystkie słowa kluczowe języka Java były zastrzeżone w pierwszej wersji JavaScript • Najważniejsze różnice między

43

this w funkcjach zagnieżdżonych (1/5)

var person =

{ fname: "John",

greet: function () {

var innerGreet = function() {

console.log("Hi! I'm " + this.fname);

};

innerGreet();

}

};

person.greet(); // undefined

• Problem: Funkcja zagnieżdżona w metodzie nie przejmuje od niej ustawienia this (this nie należy do domknięcia)

Page 44: Język programowania JavaScript · 2020. 4. 6. · – Wszystkie słowa kluczowe języka Java były zastrzeżone w pierwszej wersji JavaScript • Najważniejsze różnice między

44

this w funkcjach zagnieżdżonych (2/5)

var person =

{ fname: "John",

greet: function () {

var self = this;

var innerGreet = function() {

console.log("Hi! I'm " + self.fname)

};

innerGreet();

}

};

person.greet(); // John

• Rozwiązanie 1: Jawne przekazanie this do funkcji zagnieżdżonej przez pomocniczą zmienną w ramach domknięcia

– Idiom „self = this” (that, me, …)

Page 45: Język programowania JavaScript · 2020. 4. 6. · – Wszystkie słowa kluczowe języka Java były zastrzeżone w pierwszej wersji JavaScript • Najważniejsze różnice między

45

this w funkcjach zagnieżdżonych (3/5)

var person =

{ fname: "John",

greet: function () {

var innerGreet = function() {

console.log("Hi! I'm " + this.fname);

};

innerGreet.call(this);

}

};

person.greet(); // John

• Rozwiązanie 2: Jawne przekazanie this poprzez wywołanie funkcji zagnieżdżonej funkcją call lub apply

Page 46: Język programowania JavaScript · 2020. 4. 6. · – Wszystkie słowa kluczowe języka Java były zastrzeżone w pierwszej wersji JavaScript • Najważniejsze różnice między

46

this w funkcjach zagnieżdżonych (4/5)

var person =

{ fname: "John",

greet: function () {

var innerGreet = function() {

console.log("Hi! I'm " + this.fname);

};

var boundInnerGreet = innerGreet.bind(this);

boundInnerGreet(); }

};

person.greet(); // John

• Rozwiązanie 3: Wykorzystanie funkcji dowiązanej

Page 47: Język programowania JavaScript · 2020. 4. 6. · – Wszystkie słowa kluczowe języka Java były zastrzeżone w pierwszej wersji JavaScript • Najważniejsze różnice między

47

this w funkcjach zagnieżdżonych (5/5)

var person =

{ fname: "John",

greet: function () {

var innerGreet =

() => { console.log("Hi! I'm " + this.fname) };

innerGreet();

}

};

person.greet(); // John

• Rozwiązanie 4: Wykorzystanie funkcji strzałkowej (ES6)

– Funkcje strzałkowe nie posiadają własnego ustawienia this (używana jest wartość this z otaczającego kontekstu)

Page 48: Język programowania JavaScript · 2020. 4. 6. · – Wszystkie słowa kluczowe języka Java były zastrzeżone w pierwszej wersji JavaScript • Najważniejsze różnice między

48

Klasy (ES6)

class Shape {

constructor (id, x, y) {

this.id = id

this.move(x, y)

}

move (x, y) {

this.x = x

this.y = y

}

}

var shape = new Shape(101, 10, 20);

• Inny sposób definiowania funkcji konstruktorowych z prototypami („mostly syntactic sugar”)

– Składnia bardziej naturalna dla programistów migrujących z języków C++, C#, Java

– Klasy w JS nie są obiektami, tylko funkcjami

• Nie ma w JS:

– przeciążania metod i konstruktorów,

– deklaracji pól

– widzialności składowych

– specyfikacji typów

Page 49: Język programowania JavaScript · 2020. 4. 6. · – Wszystkie słowa kluczowe języka Java były zastrzeżone w pierwszej wersji JavaScript • Najważniejsze różnice między

49

Dziedziczenie (ES6)

class Rectangle extends Shape {

constructor (id, x, y, width, height) {

super(id, x, y)

this.width = width

this.height = height

}

}

class Circle extends Shape {

constructor (id, x, y, radius) {

super(id, x, y)

this.radius = radius

}

}

• Bardziej intuicyjna składnia niż przy dziedziczeniu funkcjonalności obiektów z prototypów

Page 50: Język programowania JavaScript · 2020. 4. 6. · – Wszystkie słowa kluczowe języka Java były zastrzeżone w pierwszej wersji JavaScript • Najważniejsze różnice między

50

Metody statyczne (ES6)

class First {

static show () {

console.log("First")

}

}

First.show()

class Second extends First {

static show() {

console.log("Second extends")

super.show()

}

}

Second.show()

• Wołane ZAWSZE na rzecz klasy, dziedziczone

Page 51: Język programowania JavaScript · 2020. 4. 6. · – Wszystkie słowa kluczowe języka Java były zastrzeżone w pierwszej wersji JavaScript • Najważniejsze różnice między

51

Gettery i settery w klasach (ES6)

class Rectangle {

constructor (width, height) {

this._width = width

this._height = height

}

set width(width) { this._width = width}

get width() { return this._width}

set height(height) { this._height = height}

get height() { return this._height}

get area() { return this._width * this._height }

}

var r = new Rectangle(5, 3)

r.width = 6

console.log(r.area)

• Problem prywatności „wewnętrznych” składowych

Page 52: Język programowania JavaScript · 2020. 4. 6. · – Wszystkie słowa kluczowe języka Java były zastrzeżone w pierwszej wersji JavaScript • Najważniejsze różnice między

52

Obsługa wyjątków

• Instrukcja throw

– Rzucić można wszystko (np. number, string), ale zalecane rzucanie obiektów Error lub podtypów

• Natywne typy wyjątków

– EvalError, RangeError, ReferenceError, SyntaxError, TypeError, URIError

• Instrukcja try/catch/finally

– Po try musi być blok catch lub finally (mogą być oba)

– finally wykonuje się niezależnie od tego czy w bloku try wystąpił wyjątek czy nie

– W bloku catch można sprawdzić rodzaj wyjątku operatorem instanceof

Page 53: Język programowania JavaScript · 2020. 4. 6. · – Wszystkie słowa kluczowe języka Java były zastrzeżone w pierwszej wersji JavaScript • Najważniejsze różnice między

53

Wyjątki – Przykład (ES6)

class MyError extends Error {

constructor(m) {

super(m);

this.name = this.constructor.name;

}

}

try {

throw new MyError("Fatal error");

}

catch (e) {

if (e instanceof MyError) {

console.log(e.message); // Fatal error

console.log(e.name); // MyError

}

else

console.log('Unknown Error');

}

Page 54: Język programowania JavaScript · 2020. 4. 6. · – Wszystkie słowa kluczowe języka Java były zastrzeżone w pierwszej wersji JavaScript • Najważniejsze różnice między

54

Terminologia dotycząca JS

• Minification

• Obfuscation

• Vanilla JS

• Unobtrusive JS

• Polyfill

Page 55: Język programowania JavaScript · 2020. 4. 6. · – Wszystkie słowa kluczowe języka Java były zastrzeżone w pierwszej wersji JavaScript • Najważniejsze różnice między

55

JSON (JavaScript Object Notation)

• Tekstowy format danych do reprezentacji i transmisji obiektów zawierających pary atrybut:wartość

• Wywodzi się z języka JavaScript (serializacja obiektów)

• Obecnie parsowanie i generacja JSON wspierane przez różne języki programowania

• Wiele różnych zastosowań

– RESTful Web Services

– AJAX (AJAJ)

– Bazy danych NoSQL

• Typ MIME: application/json

• Rozszerzenie pliku: .json

Page 56: Język programowania JavaScript · 2020. 4. 6. · – Wszystkie słowa kluczowe języka Java były zastrzeżone w pierwszej wersji JavaScript • Najważniejsze różnice między

56

Składnia i typy danych JSON

• Podstawowe typy danych

– Number (NaN niedozwolony, nierozróżnialne całk. i zmiennoprzec.))

– String (Unicode, cudzysłowy jako ograniczniki, \ jako escape)

– Boolean (true/false)

– Obiekty: { atrybut1 :wartość1, atrybut2 :wartość2, … }

– Tablice: [element1, element2, … ]

– null

• Białe spacje nie mają znaczenia

• Brak możliwości komentarzy

Page 57: Język programowania JavaScript · 2020. 4. 6. · – Wszystkie słowa kluczowe języka Java były zastrzeżone w pierwszej wersji JavaScript • Najważniejsze różnice między

57

JSON - Przykład

{

"firstName": "Marek",

"lastName": "Wojciechowski",

"age": 43,

"married": true,

"languages": [

"Polish",

"English",

"German",

"Russian",

"Spanish"

],

"phoneNumber": {

"type": "mobile",

"number": "666 444 333"

}

}

Page 58: Język programowania JavaScript · 2020. 4. 6. · – Wszystkie słowa kluczowe języka Java były zastrzeżone w pierwszej wersji JavaScript • Najważniejsze różnice między

58

Generacja JSON w JavaScript

• JSON.stringify(value[, replacer[, space]])

– Zwraca String reprezentujący przekazaną wartość

– Opcjonalne parametry umożliwiają:

• Zmianę zachowania procesu serializacji

• Dodanie białych spacji dla czytelności

– Uwagi o sposobie działania:

• Nie gwarantuje zachowania kolejności właściwości obiektów niebędących tablicami

• Obiekty typów String, Boolean i Number są zamieniane na odpowiadające wartości proste

• Wartości undefined i funkcje są:

– W obiektach: pomijane

– W tablicach: zamieniane na null

• Nie-enumerowalne właściwości (niewidoczne dla pętli for … in) są ignorowane

Page 59: Język programowania JavaScript · 2020. 4. 6. · – Wszystkie słowa kluczowe języka Java były zastrzeżone w pierwszej wersji JavaScript • Najważniejsze różnice między

59

Parsowanie JSON w JavaScript

• JSON.parse(text[, reviver])

– Wynikiem jest Object

– Gdy parsowany tekst nie jest poprawnym zapisem JSON, rzucany jest wyjątek SyntaxError

– Opcjonalna funkcja reviver umożliwia transformację parsowanych wartości

• eval()

– Funkcja do wartościowania dynamicznych wyrażeń

– Wykorzystuje fakt, że składnia JSON jest (prawie) podzbiorem składni JavaScript

– Potencjalnie niebezpieczna jeśli tekst do parsowania pochodzi z niepewnego źródła (np. zagnieżdżone funkcje)

Page 60: Język programowania JavaScript · 2020. 4. 6. · – Wszystkie słowa kluczowe języka Java były zastrzeżone w pierwszej wersji JavaScript • Najważniejsze różnice między

60

Parsowanie i generacja JSON w JavaScript - Przykład

var person = {firstName: "Marek", lastName: "Wojciechowski",

age: 43, salary: undefined, married: true,

languages: ['Polish','English','German']};

console.log(JSON.stringify(person));

var json = '{"firstName":"Marek","lastName":"Wojciechowski",' +

'"age":43,"married":true,' +

'"languages":["Polish","English","German"]}';

person1 = JSON.parse(json);

console.log(person1.firstName);

person2 = eval('(' + json + ')'); // w ogólności niebezpieczne

console.log(person2.firstName);

Page 61: Język programowania JavaScript · 2020. 4. 6. · – Wszystkie słowa kluczowe języka Java były zastrzeżone w pierwszej wersji JavaScript • Najważniejsze różnice między

61

Modularność kodu w JavaScript

• Przed ES2015

– Wzorzec programowy modułu

– Niekompatybilne ze sobą standardy opracowane przez społeczność:

• CommonJS

– Implementacja w node.js

– Zaprojektowany dla synchronicznego ładowania modułów

– Dla zastosowań serwerowych

• Asynchronous Module Definition (AMD)

– Popularna implementacja: RequireJS

– Zaprojektowany dla asynchronicznego ładowania modułów

– Dla zastosowań w przeglądarce

• Od ES2015

– Modularność wbudowana w język (składnia export / import)

Page 62: Język programowania JavaScript · 2020. 4. 6. · – Wszystkie słowa kluczowe języka Java były zastrzeżone w pierwszej wersji JavaScript • Najważniejsze różnice między

62

Cele stosowania modułów

• Podział kodu na małe pliki, z których każdy zawiera kod odpowiedzialny za pewną funkcjonalność

• Współdzielenie kodu między aplikacjami

• Używanie gotowych, sprawdzonych rozwiązań

• Ukrywanie szczegółów implementacyjnych

• Separacja „przestrzeni nazw” (nazwy zmiennych, funkcji, itd.) dla kodu z różnych źródeł

– Uniknięcie „wyciekania” nazw do globalnej przestrzeni nazw, a przez to możliwych kolizji nazw

• Zarządzanie zależnościami

Page 63: Język programowania JavaScript · 2020. 4. 6. · – Wszystkie słowa kluczowe języka Java były zastrzeżone w pierwszej wersji JavaScript • Najważniejsze różnice między

63

Wzorzec modułu

• Cel stosowania: lokalność nazw importowanego kodu

• Wykorzystane mechanizmy:

– immediately-invoked function expression (IIFE, „iffy”)

– domknięcie (ang. closure)

var module = (function () {

// private

var multiply = function (x,y) { return x * y; };

var value = 5;

...

// public

return {

multiplyByValue: function (num) {

return multiply(num, value);

},

...

}

};

})();

console.log(module.multiplyByValue(10));

Page 64: Język programowania JavaScript · 2020. 4. 6. · – Wszystkie słowa kluczowe języka Java były zastrzeżone w pierwszej wersji JavaScript • Najważniejsze różnice między

64

Moduły ES2015

• Standard natywnych modułów w ramach języka JavaScript

• Cechy:

– Dla zastosowań serwerowych i w przeglądarce

– Przewiduje synchroniczne i asynchroniczne ładowanie modułów

– Zawartość modułu domyślnie w trybie strict

– Zawartość domyślnie prywatna; to co ma być udostępnione na zewnątrz należy jawnie wyeksportować (export)

– Statyczny charakter modułów (tj. nie trzeba uruchomić kodu modułu by określić co eksportuje)

– Deklaratywne (import) lub programowe (System.import()) ładowanie modułów

Page 65: Język programowania JavaScript · 2020. 4. 6. · – Wszystkie słowa kluczowe języka Java były zastrzeżone w pierwszej wersji JavaScript • Najważniejsze różnice między

65

Moduły ES2015 – export / import

import { square, PI } from './math';

console.log(PI*square(5));

export const PI = 3.14;

export function square(x) {

return x * x;

}

main.js

math.js

Page 66: Język programowania JavaScript · 2020. 4. 6. · – Wszystkie słowa kluczowe języka Java były zastrzeżone w pierwszej wersji JavaScript • Najważniejsze różnice między

• Moduł może wskazać swój jeden, najważniejszy składnik jako domyślny eksport

– Składnia głównie z myślą o modułach eksportujących jeden składnik, ale oprócz domyślnego eksportu moduł może eksportować również inne składowe jako eksporty nazwane

66

Moduły ES2015 – domyślne eksporty

import myFunction from 'myFunction';

import MyClass from 'MyClass';

console.log(myFunction(5));

var obj = new MyClass();

export default class {

}

main.js

MyClass.js

export default function (x) {

return x * x;

}

myFunction.js

Page 67: Język programowania JavaScript · 2020. 4. 6. · – Wszystkie słowa kluczowe języka Java były zastrzeżone w pierwszej wersji JavaScript • Najważniejsze różnice między

67

Przetwarzanie asynchroniczne w JavaScript

• Przetwarzanie asynchroniczne jest zdecydowanie preferowane przy odwołaniu do zewnętrznych zasobów (np. Ajax)

– Silniki JavaScript są jednowątkowe („by design”)

• Wyjątek: worker threads

– Wywołania synchroniczne blokowałyby działanie programu/strony

• Sposoby implementacji asynchronicznego kodu w JS:

– Funkcje wywołań zwrotnych (ang. callback)

– Obietnice (ang. promise) – od ES2015

– Składnia async / await – od ES2017

• Bazuje na obietnicach i generatorach

– Programowanie reaktywne

• Reactive Extensions, RxJS

– Generatory – od ES2015

Page 68: Język programowania JavaScript · 2020. 4. 6. · – Wszystkie słowa kluczowe języka Java były zastrzeżone w pierwszej wersji JavaScript • Najważniejsze różnice między

68

Wywołania zwrotne

• Funkcja wołana asynchronicznie otrzymuje jako argumenty funkcję, która będzie wywołana po zakończeniu przetwarzania

– Callback otrzymuje wynik przetwarzania jako swój argument

– Może być przekazana więcej niż jedna funkcja callback, np. jedna do obsługi zakończenia przetwarzania sukcesem, druga do obsługi błędu przetwarzania

– Zagnieżdżanie wywołań zwrotnych prowadzi do nieczytelnych programów (tzw. callback hell)

setTimeout(function() { console.log("callback!");}, 1000);

console.log("normal flow!");

setTimeout(() => { console.log("callback!");}, 1000);

console.log("normal flow!");

Page 69: Język programowania JavaScript · 2020. 4. 6. · – Wszystkie słowa kluczowe języka Java były zastrzeżone w pierwszej wersji JavaScript • Najważniejsze różnice między

69

Obietnice (ang. Promise)

• Obietnica = obiekt reprezentujący zakończenie w przyszłości asynchronicznego przetwarzania (pozytywne lub z błędem)

function doSomething() {

return new Promise((resolve, reject) => {

...

if (success) {

resolve(result)

} else {

reject(error_info)

}

})

}

const promise = doSomething();

promise.then(successCallback, failureCallback);

// lub

// doSomething().then(successCallback, failureCallback);

Page 70: Język programowania JavaScript · 2020. 4. 6. · – Wszystkie słowa kluczowe języka Java były zastrzeżone w pierwszej wersji JavaScript • Najważniejsze różnice między

70

Łańcuchowanie obietnic

• Rozwiązanie typowego problemu sekwencji operacji asynchronicznych, gdzie każda kolejna operacja ma się rozpocząć dopiero po zakończeniu poprzedniej

• Metoda then() zwraca nową obietnicę, która staje się zrealizowana nie tylko po zakończeniu oryginalnej obietnicy, ale dodatkowo po zakończeniu jednego z callbacków przekazanych do then()

• catch(errorCallback) = then(null, errorCallback)

doFirstThing().then(function(firstResult) {

return doSecondThing(firstResult);

})

.then(function(secondResult) {

...

})

.catch(handleFailureCallback);

Page 71: Język programowania JavaScript · 2020. 4. 6. · – Wszystkie słowa kluczowe języka Java były zastrzeżone w pierwszej wersji JavaScript • Najważniejsze różnice między

71

async / await

• Lukier syntaktyczny nałożony na obietnice

• Kolejny krok w stronę większej czytelności kodu

– Sekwencja asynchronicznych operacji na poziomie kodu źródłowego wygląda jak program sekwencyjny

async function complexAsyncOperation() {

try {

const firstResult = await doFirstThing();

const secondResult = await doSecondThing(firstResult);

...

} catch(error) {

handleFailureCallback(error);

}

}

Page 72: Język programowania JavaScript · 2020. 4. 6. · – Wszystkie słowa kluczowe języka Java były zastrzeżone w pierwszej wersji JavaScript • Najważniejsze różnice między

72

Programowanie reaktywne

• ang. Reactive Programming

• Deklaratywny paradygmat programowania dotyczący:

– Przetwarzania strumieni danych

– Propagacji zmian

• „książkowy” przykład: a := b + c w podejściu imperatywnym i reaktywnym

• Reactive Extensions (ReactiveX)

– Zestaw narzędzi pozwalający imperatywnym językom na obsługę sekwencji (strumieni) danych

– API dla asynchronicznego programowania w kontekście obserwowalnych strumieni danych

– RxJS = Reactive Extensions dla języka JavaScript

Page 73: Język programowania JavaScript · 2020. 4. 6. · – Wszystkie słowa kluczowe języka Java były zastrzeżone w pierwszej wersji JavaScript • Najważniejsze różnice między

73

ReactiveX: strumienie i obserwatorzy

• Obserwowalny (ang. observable) strumień

– Emituje 3 rodzaje zdarzeń:

• next

• error

• complete

• Obserwator (ang. observer)

– Subskrybuje obserwowalny strumień

– Otrzymuje kolejne elementy ze strumienia pojedynczo (zazwyczaj poprzez funkcję callback)

– Przetwarza dane ze strumienia sekwencyjnie:

• Kolejny element nie zostanie mu dostarczony do powrotu z callbacka przetwarzającego poprzedni element

• Dane przetwarzane z zachowaniem porządku ze strumienia

Page 74: Język programowania JavaScript · 2020. 4. 6. · – Wszystkie słowa kluczowe języka Java były zastrzeżone w pierwszej wersji JavaScript • Najważniejsze różnice między

74

RxJS - Przykład

• Przykład z https://github.com/Reactive-Extensions/RxJS

/* Get stock data somehow */

const source = getAsyncStockData();

const subscription = source

.filter(quote => quote.price > 30)

.map(quote => quote.price)

.subscribe(

price => console.log(`Prices higher than $30: ${price}`),

err => console.log(`Something went wrong: ${err.message}`)

);

/* When we're done */

subscription.dispose();

Page 75: Język programowania JavaScript · 2020. 4. 6. · – Wszystkie słowa kluczowe języka Java były zastrzeżone w pierwszej wersji JavaScript • Najważniejsze różnice między

75

RxJS – Tworzenie i konwersja do obserwowalnych strumieni

• Tworzenie (jedna z możliowości)

• Konwersja (przykłady obsługiwanych źródeł)

var myObservable = new Rx.Subject();

myObservable.subscribe(value => console.log(value));

myObservable.next('first');

myObservable.next('second');

// z listy wartości

Rx.Observable.of('first', 'second');

// z tablicy

Rx.Observable.from(['first', 'second']);

// ze zdarzenia

Rx.Observable.fromEvent(document.querySelector('#myButton'),

'click');

// z obietnicy

Rx.Observable.fromPromise(fetch('/stockData'));

Page 76: Język programowania JavaScript · 2020. 4. 6. · – Wszystkie słowa kluczowe języka Java były zastrzeżone w pierwszej wersji JavaScript • Najważniejsze różnice między

76

Generatory

function* testGenCreator() {

var index = 0;

while(index < 3)

yield index++;

}

var gen = testGenCreator();

console.log(gen.next()); // {done: false, value: 0}

console.log(gen.next()); // {done: false, value: 1}

console.log(gen.next()); // {done: false, value: 2}

console.log(gen.next()); // {done: true, value: undefined}

• Generator = funkcja, która: – Może wygenerować wiele wartości

– Pozwala na iterację po zwracanych wartościach

– Wstrzymuje swoje działanie po wygenerowaniu wartości

– Przechowuje swój stan po wstrzymaniu

– Umożliwia przeplot z innym kodem w trakcie swojego działania

– Może być wykorzystana do generowania skończonych lub nieskończonych sekwencji wartości

Page 77: Język programowania JavaScript · 2020. 4. 6. · – Wszystkie słowa kluczowe języka Java były zastrzeżone w pierwszej wersji JavaScript • Najważniejsze różnice między

77

Generatory - Przykład

function* fibonacci() {

var fn1 = 0;

var fn2 = 1;

while (true) {

var current = fn1;

fn1 = fn2;

fn2 = current + fn1;

var reset = yield current;

if (reset) { fn1 = 0; fn2 = 1; }

}

}

var sequence = fibonacci();

console.log(sequence.next().value); // 0

console.log(sequence.next().value); // 1

console.log(sequence.next().value); // 1

console.log(sequence.next().value); // 2

console.log(sequence.next().value); // 3

console.log(sequence.next().value); // 5

console.log(sequence.next().value); // 8

console.log(sequence.next(true).value); // 0

console.log(sequence.next().value); // 1

console.log(sequence.next().value); // 1

console.log(sequence.next().value); // 2 * Przykład z developer.mozilla.org