bamboo
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights New
    • Engagement control
    • Make a copy
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Note Insights Versions and GitHub Sync Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Make a copy Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       Owned this note    Owned this note      
    Published Linked with GitHub
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    # Wykład 2. --- ## Uruchomienie kodu Javascript w vscode: potrzebujemy utworzyć plik launch.json. Zawiera on informacje jak uruchomic program. ## 1. Przydatne komendy `npm init -y` - inicjacja pliku package.json, w którym znajdują się informacje o używanych modułach. `npm install (moduł)` - zainstaluje w bieżącym projekcie pakiet (moduł) `npm install (moduł) --save` - zainstaluje moduł lokalnie oraz dodatkowo dopisze zależność do package.json `npm install (moduł) --g` - zainstaluje modułu globalnie `npm install` - odtwarza wszystkie zależności zgodnie z opisem w package.json **Node Package Manager (npm)** - narzędzie npm służy do instalacji i aktualizacji pakietów z globalnego repozytorium. Repozytorium npm jest największym repozytorium pakietów kodu. **${file}** - informacja w pliku launch.json o tym, że kompilujemy obecnie wyświetlany plik. --- ## 2. Język JavaScript JavasSript zalicza się do języków luźnotypowanych. ### 2.1 Deklarowanie zmiennych w JS ```javascript= var a = 12; // oznacza zmienną, ma zasięg funkcyjny, obecnie zastąpione przez poniższe: let b = 23; // oznacza zmienną, ma zasięg blokowy const c = 34; // oznacza stałą, ma zasięg blokowy ``` ### 2.2 Typy w JavaScript: **Typy proste (prymitywne)** – proste typy danych, wartości, nie można do nich dodawać składowych, są reprezentowane w pamięci jako tablice bajtów W JavaScript mamy następujące typy proste: * `null` * `undefined` * `boolean` * `string` * `number` w reprezentacji `IEEE 754`, obiekt Math (każda liczba jest 64-bitową liczbą zmiennoprzecinkową) ```javascript= var num = 20; // prosta liczba var text = "To jest tekst"; // prosty łańcuch znaków var p = true; // logiczny - prawda/fałsz var n = null; // nic var x; // zmienna z nieokreśloną wartością ``` **Typy złożone (referencyjne)** - obiekty, są reprezentowane jako „referencje” do pamięci zawierającej stany obiektów ```javascript= var a = { }; a.foo = 123; // dodawanie składowych do obiektu a['foo'] = 234; // to jest prawie równoważne, ale pozwala np. definiować klucze zawierające spację a['fo o'] = 345; ``` Każdy obiekt ma zdefiniowane funkcje `ToString()` oraz `valueOf()`, które można przeciążyć. `Object.keys(obiekt)` wypisuje klucze obiektu ### 2.3 Typy opakowujące ```javascript= var a = 1; a.foo = 'foo'; console.log( a.foo ); // wypisze undefined, bo a jest typu prostego var b = Number(1); // równoważne z powyższym b.foo = 'foo'; console.log( b.foo ); // wypisze undefined, bo a jest typu prostego var c = new Number(1); c.foo = 'foo'; console.log( c.foo ); // wypisze 'foo', bo tworzymy obiekt reprezentujący wartość 1 ``` ### 2.4 Konwersja (koercja) typów w JS **Typy konwertowane do false**: 0, -0, NaN, "", false **Operatory logiczne:** * `!` -> not * `||` -> or (jest leniwy tzn na poczatku jest wyliczana wartosc pierwszego wyrazenia i dopiero gdy okaze sie ono false to przechodzimy do drugiego wyrazenia) * `&&` -> and **Przykładowe konwersje:** ```javascript= var p = {}; console.log( p ); // Object console.log( !p ); // false console.log( !p+[] ); // 'false' console.log( [] ); // [] console.log( +[] ); // 0 console.log( (!p+[])[+[]] ); // 'f' ``` ### 2.5 typeof, instanceOf ```javascript= var a = 1; console.log( typeof a ); // zwraca napis reprezentujący typ if ( a instanceof Number ) { // sprawdza czy coś jest instancją obiektu console.log( 'Number' ); } ``` ### 2.6 Operatory porównania * `==` -> "luźne" porównanie, sprawdza czy wartości są takie same, ale po dokonaniu konwersji typów * `===` -> "dokładne porównanie", sprawdza czy wartości są dokładnie takie same ### 2.7 Napisy * "" ograniczniki zwykłego napisu * `` ograniczniki szablonu (*${zmienna}*) **Przydatne metody** * `toLowerCase()` Metoda ta konwertuje cały ciąg znaków na małe litery. * `toUpperCase()` Metoda ta konwertuje cały ciąg znaków na duże litery. * `replace(oldChar, newChar)` Zamienia wszystkie wystąpienia określonego znaku (oldChar) na nowy znak (newChar). * `trim()` Usuwa wszystkie spacje z początku i końca ciągu znaków. * `indexOf(substring)` Zwraca indeks pierwszego wystąpienia określonego podciągu znaków (substring) w ciągu. Jeśli nie znajdzie, zwraca -1. * `startsWith(prefix)` Sprawdza, czy ciąg znaków zaczyna się od określonego prefiksu (prefix). Zwraca true, jeśli tak, w przeciwnym razie false. * `endsWith(suffix)` Sprawdza, czy ciąg znaków kończy się określonym sufiksem (suffix). Zwraca true, jeśli tak, w przeciwnym razie false. ### 2.8 Getter/Setter JavaScript posiada lukier syntaktyczny do definiowania właściwości obiektu, wymagający określenia akcesorów `get` i `set`. ```javascript= var foo = { num : 0, get bar() { return foo.num; }, set bar(i) { foo.num = i; } } console.log( foo.bar ); // wypisze 0 foo.bar = 5; console.log( foo.bar ); // wypisze 5 ``` Możliwe jest ogólniejsze podejście, użycie `Object.defineProperty` za pomocą którego można dodać do obiektu dowolną wartość (pole, właściwość, funkcję) ```javascript= var foo = { } Object.defineProperty(foo, 'qux', { get: function () { return 18; } }); Object.defineProperty(foo, 'baz', { value: function () { return 34; } }); console.log(foo.qux); // wypisze 18 console.log(foo.baz()); // wypisze 34 ``` ### 2.9 Tablice * `slice(start, end)` Wybiera fragment listy na podstawie podanych indeksów. * `splice(index, k, item1, ...)` Modyfikuje tablicę poprzez usuwanie (k) i/lub dodawanie elementów (item1, ...) od danego indeksu (index). * `filter(function)` Filtruje elementy tablicy na podstawie zdefiniowanego warunku (function). * `map(function)` Wykonuje określoną funkcję (function) dla każdego elementu tablicy i zwraca nową listę zawierającą wyniki. ### 2.10 JSON ```javascript= var p = { a : 1, b : { c : 2 } } console.log(p) // zwroci {a :1, b : {...}} var s = JSON.stringify(p) console.log(p) // zwroci {"a":1, "b":{ "c":2}} console.log(s) // ``` ### 2.11 Nawiasowanie ```javascript= function a() { } // tak dobrze function a() { } // tak nie robimy bo domyslnie w javascript sa wstawiane sredniki na koncu linii moze to prowadzic do komplikacji ``` ![image](https://hackmd.io/_uploads/rkSXkGHY1e.png) ![image](https://hackmd.io/_uploads/B1bo1fBFye.png) ### Lista 2 **Zadanie 2** ```javascript= // 1. Użycie argumentów innego typu niż string dla operatora [] dostępu do składowej obiektu. // Co się dzieje jeśli argumentem operatora jest liczba? const person = { 1: "Jakub", 2: 20 }; console.log(person[1]); // wypisze "Jakub" // 2. Użycie argumentów innego typu niż number dla operatora [] dostępu do tablicy. // Co się dzieje jeśli argumentem operatora jest inny obiekt? const k = { prop: "1" }; console.log(person[k.prop]); // Wypisze "Jakub" // Co się dzieje jeśli argumentem operatora jest napis? const fruits = ["apple", "orange", "banana"]; console.log(fruits["1"]); //Wypisze "orange" // Co się dzieje jeśli argumentem operatora jest inny obiekt dla tablic? const key2 = { prop: "1" }; console.log(fruits[key2.prop]); // wypisze "orange" // Czy i jak zmienia się zawartość tablicy jeśli zostanie do niej dopisana właściwość pod kluczem, który nie jest liczbą? fruits["2"] = "strawberry"; // wstawi "strawberry" na miejscu o indeksie 2 // Czy można ustawiać wartość atrybutu length tablicy na inną wartość niż liczba elementów w tej tablicy? fruits.length = 10; console.log(fruits.length) // wypisze 10 fruits.length = 2; console.log(fruits.length) // wypisze 2 ``` # Wykład 3. ## 1. Funkcje ### 1.1 Zmienna ilość argumentów Operator rozrzucania, czyli trzykropek: `...` pozwala na użycie dowolnej ilości argumentów w funkcji. ```javascript= function(...args) { for (let i = 0; i < args.length; i++) { console.log(args[i]) } } ``` ### 1.2 Funkcje anonimowe ```javascript= function(x) { x > 2 } (x) => { x > 2 } ``` ### 1.3 Funkcja w funkcji Aby wywołać funkcję w funkcji należy podać jej argumenty w drugim nawiasie. ```javascript= function create() { return function () { return 1; } } console.log(create()) // wypisze [Function (anonymous)] console.log(create()()); // wypisze 1 ``` ### 1.4 Domknięcie funkcji **Domnknięcie funkcji** to dodatkowy obiekt wiążący funkcję ze środowiskiem. ```javascript= function sumpartial(x) { return (y) => { return x + y; } } var sum1 = sumpartial(1); console.log(sum1(2)); console.log(sumpartial(1)(2)) ``` Nieskończona ilość aplikowalnych argumentów: ```javascript= function sumpartial(x) { var acc = x; // nasz akumulator "zapamiętujący" obecną sumę var func = (y) => { acc += y; return func; } func.valueOf = () => { return acc; } return func; } console.log(+sumpartial(4)(5)(6)); ``` ### 1.5 Memoizacja Przydaje się zwłaszcza w przypadku, gdy funkcja w argumencie jest rekurencyjna (np. ciąg Fibonacciego) ```javascript= function memo(func){ var cache = {} return function(n){ if (n in cache){ return cache[n]; } else{ var result = func(n); cache[n] = result; return result; } } } ``` ### 1.6 IIFE Funkcja jest wywołana zaraz po zdefiniowaniu. Let to lukier syntaktyczny dla IIFE, obie poniższe definicje są sobie równoważne i zmienna k ma zasięg blokowy. ```javascript= { (function() { var k; }()) let k } ``` ### 1.7 Currying Currying to inaczej rozwijanie funkcji, w którym częściowa aplikacja jest możliwa dla każdego argumentu z osobna (wywołanie z n argumentami zamienia się na n wywołań z jednym argumentem). ```javascript= function sum3(x, y, z) { return x + y + z; } function curry(fn) { function rec(fn, i, args) { if (i < fn.length) { return (x) => { args.push(x); return rec(fn, i + 1, args); } } else { return fn(...args); } } return rec(fn, 0, []); } var currysum3 = curry(sum3); console.log(currysum3(1)(2)(3)); ``` ### 1.8 this, call, bind, apply * **this** W funkcji wywołanej z wiązaniem na obiekcie(`o.funkcja()`), `this` ma wartość referencji do tego obiektu. ```javascript= var person = { name: 'jan', say: function () { return this.name; } } console.log(person.say()); ``` Alternatywnie: ```javascript= var person = { name: 'jan', say: say // lub po prostu say } function say() { return this.name } console.log(person.say()); ``` * **call** Służy do wywołania funkcji, gdzie argumentem jest obiekt, w którego kontekście ma być wywołana. Argumentami `call` jest to, co ma być widoczne jako `this`, wewnątrz funkcji. ```javascript= var person = { name: 'jan', } function say() { return this.name } console.log(say.call(person)); ``` * **apply** Działa bardzo podobnie do `call`, z tą różnicą że argumenty są przekazywane jako lista, nie po przecinku jak w `call`. Poniższe zapisy są sobie równoważne: ```javascript= function f(a, b, c){ return this, a, b, c } var o = { x: 1 } f.apply(o, [1, 2, 3]) f.call(o, 1, 2, 3) ``` * **bind** Bind zaaplikowany do funkcji, zwraca inną funkcję, w której `this` już jest zawsze zamieniony na jakiś obiekt. ```javascript= function foo(y, z) { return this.x + y + z; } var o = { x: 1 } var baz = foo.bind(o); console.log(baz(1, 2)); // wypisze 4 ``` ## 2. Iteratory, generatory ### 2.1 Iterator **Iterator** to funkcja bezargumentowa która zwraca obiekt, który ma jedno pole, `next`, które jest funkcją zwracającą obiekt o polach `value` i `done`. ```javascript= function createIterator() { var acc = 0; return { next: function () { return { value: acc, done: acc++ >= 10 } } } } var it = createIterator(); for (var result; result = it.next(), !result.done;) { console.log(result.value); } ``` Funkcja iteratora jeśli zostanie użyta w obiekcie jako wartość składowej `Symbol.iterator`, obiekt uzyskuje możliwość iterowania jego zawartości za pomocą for-of. ```javascript= var foo = { [Symbol.iterator]: createIterator } for (var f of foo) { console.log(f); } ``` W obu przypadkach zostaną wypisane liczby od 0 do 9. ### 2.2 Generator **Generator** to skrócony sposób zapisu kodu iteratora, dodający zwracanie bieżącej wartości za pomocą `yield`. Iterowanie generatora działa tak samo jak iteratora. ```javascript= function* createGenerator() { for (var i = 0; i < 10; i++) { yield i; } } ``` Gwiazdka przy `function` jest niezbędna. Pętla for, oraz for-of działają tak samo jak w iteratorze. ### 2.3 Próba oszustwa Iterator/Generator powinien być funkcją bezargumentową, ale jednak chcemy przekazać mu jakieś wartości. Można po prostu zwrócić funkcję bezargumentową. ```javascript= function createGenerator(n) { return function* () { for (var i = 0; i < n; i++) { yield i; } } } var foo = { [Symbol.iterator]: createGenerator(10) } for (var val of foo) { console.log(val); // wypisze liczby od 0 do 9 } ``` ### Lista 3 **Zadanie 2** ```javascript= function forEach(a, f){ if (a[0] === undefined){ return [undefined]; } else{ f(a[0]); forEach(a.slice(1), f); } } function map(a, f){ if (a.length == 0){ return []; } else{ return [(f(a[0])), ...map(a.slice(1), f)]; } } function filter(a, f){ if (a.length == 0){ return []; } else if (f(a[0])){ return [a[0], ...filter(a.slice(1), f)] } else{ return [...filter(a.slice(1), f)] } } ``` --- # Wykład 4. ## 1. Paradygmat obiektowy **Projektowanie obiektowe** - określanie odpowiedzialności obiektów (klas) i ich relacji względem siebie. Wszystkie dobre praktyki, zasady, wzorce sprowadzają się do tego jak właściwie rozdzielić odpowiedzialność na zbiór obiektów (klas). W JavaScript jeżeli dwa niepowiązane ze sobą w żaden sposób obiekty mają „podobny wygląd” (pola/metody), to obu można użyć w tym samym kontekście i do tego nie jest potrzebna żadna kontrola typów: ```javascript= var person = { name: 'jan', say: function () { return this.name; } } var car = { brand: 'skoda', say: function () { return this.brand; } } function describe(item) { console.log(item.say()); } describe(person); describe(car); ``` Jest to tzw. **Duck Typing**, czyli rozpoznawanie typu obiektu poprzez pola, które zawiera. *„If it walks like a duck and it quacks like a duck, then it must be a duck.”* W Javascript są trzy równoważne modele implementowania struktur obiektów: * `{}` * `new` * `Object.create()` W językach takich jak C# czy Java jest tylko jeden sposób tworzenia nowych instancji obiektów – to operator `new` ## 2. Obiektowość z { }, bez dziedziczenia Pierwsza technika obiektowości w JS to 'udawanie' konstruktorów, poprzez proste funkcje tworzące obiekty. Wadą jest jednak niepotrzebne zużycie pamięci na kopiowanie metod. ```javascript= function Person(name, surname) { return { name: name, surname: surname, say: function () { return `${this.name} ${this.surname}`; } } } var p = Person('jan', 'kowalski'); console.log(p.say()); ``` ## 3. Obiektowość prototypowa Obiektowość prototypowa zestawia wiele instancji obiektów w łańcuchy, w których każdy obiekt wskazuje na swój prototyp. ### 3.1 Prototyp Prototyp to taki "poprzednik" istniejącego obiektu. Nadrzędnym prototypem każdego obiektu jest `Object.prototype`, z którego każdy inny obiekt dziedziczy metody np. `toString()` albo `valueOf()`. * Aby zmienić prototyp używamy funkcji: `Object.setPrototypeOf(obiekt, nowyPrototyp)` * Aby odczytać prototyp istniejącego obiektu używamy funkcji: `Object.setPrototypeOf(obiekt)` ```javascript= var o = { foo: null } var proto = { foo: 1, bar: 2 } Object.setPrototypeOf(o, proto); console.log(o.foo); // wypisze null console.log(o.bar); // bar pochodzi z obiektu proto, wypisze 2 console.log(o.foo); // wypisze null ``` #### Ograniczenia * Obiekt może mieć pusty prototyp. W szczególności, ten prototyp wszystkich obiektów, czyli `Object.prototype`, ma pusty prototyp. Dzięki temu łańcuch prototypów zawsze się kończy. * Łańcuch prototypów nie może mieć cykli. Dosyć logiczne. ## 4. Obiektowość z new W JavaScript obiektowość z użyciem słowa kluczowego `new` odnosi się do tworzenia nowych instancji obiektów przy użyciu konstruktorów. ```javascript= function Person(name, age) { this.name = name; this.age = age; } // dodawanie nowych metod, prototyp wszystkich nowych instancji obiektu: Person.prototype.say = function () { return this.name; }; var person = new Person("Jan", 21); console.log(person.age); ``` Wewnątrz konstruktora `this` odnosi się do nowo tworzonej instancji obiektu. Możemy też łatwo modyfikować pola nowych instancji: ```javascript= person.age = 22 console.log(person.age); // wypisze 22 ``` #### Dziedziczenie Możemy w łatwy sposób osiągnąć coś na wzór dziedziczenia: ```javascript= var Worker = function (name, surname, age) { Person.call(this, name, age); this.surname = surname; } // ustawienie prototypu dla worker Worker.prototype = Object.create(Person.prototype); var worker = new Worker('jan', 'kowalski', 48); console.log(worker.say()); ``` Dodanie nowej funkcjonalności (pola lub funkcji) do prototypu automatycznie dodaje ją do wszystkich obiektów o tym prototypie. #### Przykładowe prototypy: ```javascript= var o = {} console.log( Object.getPrototypeOf(o) === Object.prototype ); // true function foo() {} console.log( Object.getPrototypeOf(foo) === Function.prototype ); // true var s = 'ala ma kota'; console.log( Object.getPrototypeOf(s) === String.prototype ); // true ``` ## 5. Obiektowość z Object.create() Funkcja `Object.create()` tworzy nową instancję obiektu i ustawia jej wskazany obiekt jako prototyp. Konstruktor - musi być rozdzielony na tworzenie przez `Object.create` (poprawne zestawienie łańcucha prototypów) i metodę `init` która jedynie inicuje stan obiektu. ```javascript= var Person = { init: function (name, surname) { this.name = name; this.surname = surname; }, say: function () { return this.name; } } var Worker = Object.create(Person); Worker.init = function (name, surname, age) { person.init.call(this, name, surname); this.age = age; } var w = Object.create(Worker); w.init('tomasz', 'malinowski', 48); console.log(w.say()); ``` Oba sposoby implementacji obiektowości, ten w którym `Object.create()` jest pierwotne i ten w którym `new` jest pierwotne, są równoważne. ## 6. Lukier syntaktyczny definicji klas ```javascript= class Person { constructor(name, surname) { this.name = name; this.surname = surname; } say() { return this.name + this.surname; } } class Worker extends Person { constructor(name, surname, age) { super(name, surname); this.age = age; } say() { var prev = super.say(); return prev + this.age; } } var w = new Worker('tomasz', 'malinowski', 48); console.log(w.say()); ``` ## Lista 4 **Zadanie 2** Jak odróżnić składową, która pochodzi z obiektu od takiej która pochodzi z prototypu? ```javascript= var person = { name: 'jan' } var personProto = { surname: 'kowalski', age: 30 } Object.setPrototypeOf(person, personProto); // zwraca true, jeżeli obiekt zawiera takie pole function isInObject(obj, propertyName) { return obj.hasOwnProperty(propertyName); } // Wypisuje pola, również te z łańcucha prototypów for (key in person) { console.log(key); } ``` **Zadanie 3** ```javascript= var Person = function(name) { this.name = name; } var Worker = function(name, age) { Person.call(this, name); this.age = age } ``` * Poprawne podejście ```javascript= Worker.prototype = Object.create(Person.prototype); ``` Poprawna wersja z wykładu izoluje prototyp, zmiany w dziedziczącym prototypie nie wpłyną na prototyp rodzica. * Błędne podejście 1: ```javascript= Worker.prototype = Person.prototype; ``` Modyfikując `Worker.prototype`, poprzez dodanie pola/metody dodajemy je zarówno do Worker.prototype jak i do Person.prototype. * Błędne podejście 2: ```javascript= Worker.prototype = new Person(); ``` Tworzymy nowy obiekt person wywołujemy jego konstruktor. Nie przekażemy argumentów konstruktora odpowiednich dla `Worker`. **Zadanie 4** Nie można dodawać prototypów do typów prostych. Prototypem typów prostych jest `object`. **Zadanie 5** Efekt składowych prywatnych. ```javascript= function Foo() { this.Bar = function() { Qux(); } function Qux(){ // brak dostępu console.log("qux") } this.getName = function() { return _name; } var _name = name; // brak dostępu } ``` --- # Wykład 5. ## 1. Klasy ### 1.1 Przestrzenie nazw Inne języki: `namespace` JavaScript: obiekty zagnieżdżone w obiektach: ```javascript= UWr = {} UWr.weppo = {}; UWr.weppo.Person = function(name) { this.name = name; } var p = new UWr.weppo.Person('jan'); console.log(p.name); ``` ### 1.2 Moduły ```javascript= // module.js module.exports = { module_function }; ``` ```javascript= // main.js let var = require('./module'); var.module_function(5); ``` ### 1.3 Dokumentacja **JSDoc** - standard dokumentacji kodu, pozwala edytorom na wyświetlanie komentarzy, po najechaniu na funkcję napisaną przez nas. Pojawia się przed opisywaną funkcją. ```javascript= /** * Funkcja dodająca dwie liczby. * @param {number} a - Pierwsza liczba. * @param {number} b - Druga liczba. * @returns {number} Suma dwóch liczb. */ function sum(a, b) { return a + b; } ``` ## 2. Programowanie asynchroniczne :( Programowanie asynchroniczne w języku JavaScript polega na wykonywaniu operacji, które mogą trwać różną ilość czasu, bez blokowania wykonywania kolejnych instrukcji. Główne cechy programowania asynchronicznego w JavaScript to: * **Funkcje zwrotne (Callbacks)** Polega to na przekazywaniu funkcji do innych funkcji, które zostaną wykonane, gdy operacja asynchroniczna zakończy się. * **Obietnice (Promises)** Obietnice to obiekty reprezentujące wartość, która może być dostępna natychmiast lub w przyszłości. * **Funkcje async/await** Funkcje oznaczone jako async zwracają obietnice, a słowo kluczowe await używane jest do oczekiwania na zakończenie operacji asynchronicznej wewnątrz funkcji async. Podejście async-await jest równoważne callbackom. ### 2.1 Callback Hell Kolejne wywołania funkcji asynchronicznych w jednym potoku powodują konieczność charakterystycznego zagnieżdżania funkcji zwrotnych, nazwanego **Callback Hell**. Nieumiejętność radzenia sobie z tą niedogodnością struktury kodu jest jednym z powodów dla których Javascript miał przez lata tak niedobrą opinię. ```javascript= funkcja1(function(response1) { funkcja2(response1, function(response2) { funkcja3(response2, function(response3) { // i tak dalej... }); }); }); ``` ### 2.2 Promise Alternatywą dla funkcji zwrotnych jest wzorzec struktury kodu oparty na obiektach Promise. Promise jest obiektem który ma: * **Stan** (Pending, Fulfilled, Rejected) * **Funkcję do zmiany stanu** * **Listę tzw. kontynuacji** czyli funkcji, które trzeba wykonać wtedy kiedy wynik będzie dostępny `then()` lub zostanie wyrzucony wyjątek `catch()` Konytnuacja z kolei zawsze zwraca `Promise`, nawet jeśli technicznie nic nie zwraca. Dzięki temu możliwe jest łańcuchowanie wywołań. ```javascript= var promise = new Promise((resolve, reject) => { resolve(17); // zmiana stanu }); promise .then(result => { console.log(result); }) .then(result => { console.log(result + 1); }) .catch(error => { console.error(error); }); ``` ### 2.3 async/await Lukier syntaktyczny, który umożliwia pisanie asynchronicznego kodu w sposób, który wygląda jak synchroniczny, co znacznie ułatwia zarządzanie asynchronicznością i czytelność kodu. * **async**: Funkcje oznaczone jako `async` zwracają obietnice (Promise). Wewnątrz funkcji `async` możemy korzystać z słowa kluczowego `await`, które czeka na zakończenie operacji asynchronicznej i zwraca jej rezultat. * **await**: Słowo kluczowe `await` może być używane wewnątrz funkcji oznaczonej jako `async` do oczekiwania na zakończenie operacji asynchronicznej. Działanie funkcji `await` polega na "zawieszeniu" wykonywania funkcji do momentu rozwiązania obietnicy. ```javascript= function pobierzDane() { return new Promise(function(resolve) { setTimeout(function() { resolve("Dane zostały pobrane!"); }, 2000); }); } (async function dzialanie() { try { var wynik = await pobierzDane(); console.log(wynik); // "Dane zostały pobrane!" } catch (error) { console.error(error); } })(); ``` ## Lista 5 **Zadanie 1** Aby zbudować cykl modułów wystarczy na początku pliku dodać `module.exports`. ```javascript= module.exports = { test2 } const a = require('./module1.js') console.log('Module 2 loaded module 1') function test2(x){ if (x > 0){ console.log(`Module 2: ${x}`) a.test1(x - 1) } } ``` ```javascript= module.exports = { test1 } const b = require('./module2.js') console.log('Module 1 loaded module 2') function test1(x){ if (x > 0){ console.log(`Module 1: ${x}`) b.test2(x - 1) } } ``` **Zadanie 4** Odczytywanie i wypisywanie zawartości pliku. ```javascript= var fs = require('fs'); function read() { return new Promise((resolve, reject) => { fs.readFile('text.txt', 'utf-8', (err, answer) => { if (err) { reject(answer); } else{ resolve(answer); } }) }); }; (async function main() { t = await read() console.log(t) })() ``` --- # Wykład 6. ## 1. Kilka słów o TypeScript **TypeScript** to język programowania stworzony przez Microsoft, który rozszerza składnię języka JavaScript poprzez dodanie statycznego typowania. Oznacza to, że TypeScript pozwala programistom określać typy zmiennych, parametrów funkcji i innych elementów kodu, co ułatwia wykrywanie błędów i refaktoryzację kodu. #### Kilka cech TypeScript: * **Statyczne typowanie**: TypeScript umożliwia definiowanie typów zmiennych, parametrów funkcji, wartości zwracanych itp. * **Kompilacja do JavaScript**: Kod napisany w TypeScript jest kompilowany do kodu JavaScript, co oznacza, że może być uruchamiany na każdej platformie wspierającej JavaScript. Kod sprawdzany jest w momencie kompilacji. * **Obsługa klas i interfejsów:** TypeScript wspiera obiektowość poprzez koncepcje klas i interfejsów. #### Przydatne komendy: * `npm install typescript -g` - globalna instalacja TS * `tsc --init` - inicjalizacja pliku tsconfig.json * `tsc --watch` - uruchamia kompilator TypeScripta (tsc) w trybie śledzenia. Oznacza to, że kompilator będzie śledził pliki źródłowe TypeScript i automatycznie kompilował je za każdym razem, gdy zostaną zmodyfikowane. **ts-node** to środowisko uruchomieniowe TypeScript, które rozszerza node o kompilację TS „w locie”. Do tego należy używać polecenia `ts-node plik.ts`. ## 2. System typów ![image](https://hackmd.io/_uploads/ry4b3ZWip.png) * **unknown** najbardziej ogólny typ, który reprezentuje wartość, o której nie wiadomo, jakiego typu jest w momencie kompilacji. "Bezpieczniejszy" w stosunku do typu`any`. * **never** można nadać go nadać zmiennej, ale takiej zmiennej nie da się nadać żadnej wartości. Wykorzystuje się go np. w sytuacjach w których funkcja nigdy nie zakończy się, lub jej wartość nigdy nie zostanie zwrócona. **System typów TS jest znacznie bogatszy niż system typów JS.** Wynika to z tego, że o ile część typów TS i JS pokrywa się (np. zmienna zadeklarowana w TS jako `string` będzie miała w JS też typ `string`) to sporo typów zadeklarowanych w TS po prostu zniknie po kompilacji do JS (np.wszystkie typy zadeklarowane przez programistę z użyciem `type/interface`) ```typescript= // Typ prosty w TS let s: string = 's'; console.log(Object.getPrototypeOf(s) === String.prototype); // true // Typ złożony (strukturalny) w TS type Person = { name: string; surname: string; } let p: Person = { name: 'jan', surname: 'jan' } // po uruchomieniu, na poziomie JS, prototypem p jest Object.prototype // Person "znika" z pola widzenia systemu typów czasu wykonania console.log(Object.getPrototypeOf(p) === Object.prototype); //true ``` ### 2.1 Inne rodzaje typów ```typescript= // typ literalny anonimowy: typem zmiennej jest 'x' let _x1: 'x' = 'x'; // typ literalny został nazwany, X type X = 'x'; let _x2: X = 'x'; // typ strukturalny anonimowy: // typem zmiennej jest { name: string, surname: string } let _person1: { name: string, surname: string } = { name: 'jan', surname: 'kowalski' }; // typ strukturalny został nazwany, Person type Person = { name: string, surname: string }; let _person2: Person = { name: 'jan', surname: 'kowalski' } ``` #### Type vs Interface Różnice między `type` a `interface` są nieznaczne i można powiedzieć że to synonimy, z zastrzeżeniem: * `type` pozwala na tworzenie nowych, bardziej skomplikowanych typów danych, podczas gdy `interface` służy głównie do definiowania kształtu obiektów. Może zawierać tylko deklaracje właściwości i metod, ale nie implementacje. ```typescript= type Osoba = { imie: string; wiek: number; } type Adres = { ulica: string; kodPocztowy: string; } type Klient = Osoba & Adres; ``` ```typescript= interface Osoba { imie: string; wiek: number; } interface Adres { ulica: string; kodPocztowy: string; } interface Klient extends Osoba, Adres { nrTelefonu: string; } ``` ### 2.2 Inferencja typów **Inferencja typów** to mechanizm, który pozwala na automatyczne wywnioskowanie typów zmiennych na podstawie ich wartości lub kontekstu, bez konieczności jawnego określania typów przez programistę. ```typescript= type Person = { name: string, surname: string } function DoWork(p: Person): Person { // zwraca obiekt literalny - ale struktura jest zgodna! return { name: p.name + ' from doWork', surname: p.surname + " from doWork" }; } ``` Ani obiekt zwracany z funkcji, ani obiekt przekazywany do funkcji nie ma jawnie zadeklarowanego typu (choć mógłby!) i w obu przypadkach TS jest w stanie zweryfikować poprawność wywołania na podstawie wyłącznie zgodności pól. typu. **W TypeScript strukturalnie typ** `Person` **oraz typ** `{name: string, surname: string}` **są równoważne!** ### 2.3 Unie i przecięcia typów * Unia typów `|` ```typescript= // Unia typów string lub number let zmienna: string | number; zmienna = "Hello"; // OK zmienna = 10; // OK zmienna = true; // Błąd, wartość typu boolean nie jest częścią unii ``` * Przecięcie typów `&` ```typescript= // Przecięcie typów Osoba i Adres interface Osoba { imie: string; wiek: number; } interface Adres { ulica: string; kodPocztowy: string; } type Klient = Osoba & Adres; // Klient będzie zawierać właściwości imie, wiek, ulica i kodPocztowy ``` ### 2.4 Strażnik typów **Strażnik typów** zwraca informacje o przynależności obiektu do jakiegoś typu. ```typescript= type Person = { name: string } type WorkingPerson = Person & { position: string } // stażnik typowy (type guard) function isWorkingPerson(p: Person): p is WorkingPerson { return 'position' in p; } ``` ### 2.5 Przeciążenie funkcji TypeScript nie pozwala przeciążyć implementacji funkcji, ale zamiast tego pozwala na przeciążenie samej sygnatury (sposób określania typów parametrów funkcji oraz typu wartości zwracanej przez funkcję). ### 2.6 Jeszcze więcej typów #### Typy generyczne ```typescript= function identyfikator<T>(arg: T): T { return arg; } let identyfikatorString: string = identyfikator("hello"); let identyfikatorLiczba: number = identyfikator(42); ``` #### Typy indeksowane ```typescript= interface Dictionary<T> { [klucz: string]: T; } let slownik: Dictionary<number> = {}; slownik["jeden"] = 1; slownik["dwa"] = 2; ``` #### Typy funkcyjne ```typescript= type FunkcjaDodawania = (a: number, b: number) => number; let dodaj: FunkcjaDodawania = (x, y) => x + y; let wynik: number = dodaj(3, 5); // wynik: 8 ``` ### 2.7 keyof, typeof * `typeof` jest operatorem używanym do uzyskiwania typu wartości, zmiennej lub wyrażenia. * `keyof` jest operatorem używanym do uzyskiwania typu, który zawiera wszystkie klucze obiektu lub typu. ```typescript= const liczba = 42; type TypLiczby = typeof liczba; // TypLiczby zawiera typ "number" ``` ```typescript= type Osoba = { imie: string; wiek: number; email: string; }; type KluczeOsoby = keyof Osoba; // KluczeOsoby zawiera typ "imie" | "wiek" | "email" ``` ### 2.8 Typy mapowane Jeśli keyof działa tak że z typu strukturalnego wybiera klucze, to czy istnieje operacja odwrotna? Taka, że dla zadanej unii kluczy tworzy typ strukturalny z tymi kluczami? Tak. Do tego służą typy mapowane. ```typescript= type Osoba = { imie: string; wiek: number; }; type OsobaZDwomaStringami = { [K in keyof Osoba]: string; }; // OsobaZDwomaStringami będzie miało typ { imie: string, wiek: string } ``` Typy warunkowe pozwalają na wybór typu na podstawie warunku logicznego. ```typescript= type AcceptOnly<T> = T extends 'name' ? T : never; type Name = AcceptOnly<'name'> // 'name' type NoName = AcceptOnly<'noname'> // never ``` #### Inny ważny przykład ```typescript= type Person = { name: string, surname: string, age: number, position: number } // pomiń klucze type ExceptKeys<T, U> = T extends U ? never : T; // mapuj obiekt na obiekt z pominiętymi kluczami type OmitKeys<T, K extends keyof T> = { [k in ExceptKeys<keyof T, K>]: T[k] } // { // age: number. // position: number //} type WorkingPerson = OmitKeys<Person, 'name' | 'surname'> ``` ### 2.9 Kilka wbudowanych typów generycznych * `Partial<Type>` Konstruuje z zadanego typu typ, który ma wszystkie składowe opcjonalne * `Required<Type>` Konstruuje z zadanego typu typ, który ma wszystkie składowe wymagane * `Readonly<Type>` Konstruuje z zadanego typu typ, który ma wszystkie składowe tylko-do-odczytu * `Record<Keys, Type>` Konstruuje typ z zadanych kluczy i typu wartości * `Extract<Keys, Keys>` Z zadanej unii typowej zwraca wskazane elementy * `Exclude<Keys, Keys>` Z zadanej unii typowej wyrzuca wskazane elementy * `Pick<Type, Keys>` Z zadanego typu struktury zwraca podtyp ze wskazanych kluczy * `Omit<Type, Keys>` Z zadanego typu struktury zwraca podtyp z wyrzuconymi wskazanymi kluczami --- # Wykład 7 ## 1. HTTP ### 1.1 Protokół **Protokół HTTP** opracowano na początku lat 90tych. Jest to oparty o TCP/IP protokół komunikacyjny, zaprojektowany do przekazywania treści multimedialnych. Przez oparty o TCP/IP rozumiemy tu protokół, w warstwie transportowej którego używane są gniazda BSD, czyli standard z początku lat 80tych, zaadoptowany do POSIX jako de facto interoperacyjny standard komunikacyjny. Interfejs gniazd przyjął się w dużej mierze dzięki swojej prostocie konceptualnej, opartej o funkcje: - **bind**, **listen** i **accept** na serwerze - **connect** na kliencie - **send** i **recv** na kliencie i serwerze ![image](https://hackmd.io/_uploads/rkxbUlZsp.png) ### 1.2 Żądanie Tekst złożony z **wielu linii**, z których **pierwsza** określa **rodzaj żądania i nazwę zasobu**, a **kolejne linie** oznaczają tzw. **nagłówki HTTP**. **Pusta linia oznacza koniec żądania**, chyba że jest to żądanie z parametrami (np. POST czy PUT), wtedy treść żądania może być dowolnie długa. W takim przypadku obowiązkowy jest **nagłówek Content-length**, który określa **długość tej dodatkowej opcjonalnej części**. ### 1.3 Odpowiedź Tekst lub strumień binarny, interpretowany przez klienta na podstawie opisu w nagłówku **Content-type**, o długości zadanej przez nagłówek **Content-length** ### 1.4 Klienci i debuggery HTTP Przeglądarka może posiadać **funkcję podglądu sieciowego**, ponieważ podgląd odbywa się w samej przeglądarce, nie ma problemu z podglądem ruchu szyfrowanego (**HTTPs**) Zewnątrzprocesowy podgląd ruchu między klientem a serwerem możliwy jest albo za pomocą narzędzi niskopoziomowych (np. Wireshark) albo tzw. **debuggerów http** (wykorzystując to, że przeglądarki pozwalają na ustawienie tzw. **proxy** dla ruchu HTTP) > Przykładowy klient wykorzystujący POST do ścieżki https://httpbin.org/post ```javascript= var https = require('https'); function promisedRequest() { return new Promise(function (resolve, reject) { var qs = new URLSearchParams(); qs.append('foo', 'foo'); qs.append('bar', 'bar'); var postData = qs.toString(); /** * @type {http.RequestOptions} */ var requestParameters = { host: 'httpbin.org', port: '443', path: '/post', method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'Content-Length': Buffer.byteLength(postData) } }; var client = https.request(requestParameters, function (res) { var buffer = ''; res .on('data', function (data) { buffer += data.toString(); }) .on('end', function () { resolve(buffer); }); }); client.write( postData ); client.end(); }); } (async function() { var result = await promisedRequest(); console.log( result ); })(); ``` ### 1.5 Fiddler i Burp Darmowe debugery http. Oba narzędzia pozwalają na tworzenie własnych żądań - **kopiowanie i modyfikowanie istniejących** i/lub **tworzenie żądań od** **"zera"** **Node.js** posiada wsparcie dla tworzenia serwerów HTTP bezpośrednio w bibliotece standardowej, np. ```javascript var http = require("http"); var server = http.createServer( (req, res) => { //Wymuszenie interpretowania odpowiedzi w określonym kodowaniu res.setHeader('Content-type', 'text/html; charset=utf-8'); res.end(`hello world ${new Date()}`); }); server.listen(3000); console.log('started'); ``` Argumentem funkcji tworzącej jest **callback** przyjmujący dwa argumenty: - **req** typu **IncomingMessage** który jest modelem dla żądania od klienta (stąd można odczytać adres i typ żądania, nagłówki, cookies) - **res** typu **ServerResponse** który jest modelem dla odpowiedzi dla klienta Funkcje zwrotne kolejnych żądań (np. wielu użytkowników) trafiają do pętli zdarzeń i tworzą **kolejkę** oczekujących żądań. Są one obsługiwane ***jednowątkowo***. Asynchroniczność jest kluczowa do zwiększenia przepustowości - procesor przetwarza wyłącznie kod i można zrezygnować z kosztownego oczekiwania na żądanie synchroniczne do zewnętrznego zasobu. > Na przykład: > - serwer dostaje żądanie A, ustawia się w kolejce zdarzeń > - serwer dostaje żądanie B, ustawia się w kolejce zdarzeń > - serwer rozpoczyna przetwarzanie żądania A, w ramach niego zaczyna odczytywać jakiś plik > - serwer rozpoczyna przetwarzanie żądania B, w ramach niego zaczyna odczytywać jakiś plik > - ... serwer czeka w pętli aż zakończy się odczyt plików ... > - odczyt z żądania A kończy się i do pętli zdarzeń trafia kontynuacja > - odpowiedź na żądanie A jest przesyłana do klienta > - odczyt z żądania B kończy się i do pętli zdarzeń trafia kontynuacja > - odpowiedź na żądanie B jest przesyłana do klienta > > W trakcie obsługi obu żądań procesor w żadnym momencie nie czekał na odczyt danych z plików - bo w tym czasie przetwarzał inne żadania z pętli zdarzeń ### 1.6 Klaster W node.js to grupa procesów, które współdzielą ten sam port TCP. Żądanie trafia do któregoś z procesów dzielących się portem. ## 2. HTTPs Rozszerzenie protokołu **HTTP** w którym pod żądaniem typu **CONNECT** pojawia się dodatkowy tzw. **handshake** czyli **sekwencja komunikatów zmierzająca do ustalenia klucza szyfrującego komunikację** Ta część komunikacji wykorzystuje algorytm asymetryczny (RSA), gdzie **serwer** ma **klucz publiczny** (certyfikat) i **klucz prywatny** (nie ujawniony). Serwer przesyła dane do klienta, a klient używa certyfikatu do zaszyfrowania klucza do szyfrowania dalszej komunikacji. ### 2.1 Generowanie certyfikatów Ceryfikat SSL można wygenerować przy pomocy **OpenSSL**. Przemysłowe certyfikaty, mające zaufane organizacje na szczycie **łańcucha poświadczeń** można kupić lub pozyskać bezpłatnie. Najprostszy serwer HTTPs w node.js: ```javascript var fs = require('fs'); var https = require('https'); (async function () { var pfx = await fs.promises.readFile('test.pfx'); var server - https.createServer({ pfx: pfx, passphrase: 'test' }, (req, res) => { res.setHeader('Content-type', 'text/html; charset=utf-8'); res.end('hello world ${new Date()}') }); server.listen(3000); console.log('started'); }) ``` ### 2.2 HTTP/2 rozszerza protokól http o optymalizacje w warstwie transportowej: - otwiera zawsze **jedno gniazdo** między klientem a serwerem - ruch jest **kompresowany, binarny** - możliwe jest **zrównoleglanie wielu żądań i wielu odpowiedzi** - możliwe jest **przesyłanie danych** z serwera do klienta **zanim klient zrobi żądanie** ### 2.3 Rzeczywistość W pliku **etc/host** możliwe jest mapowanie DNS na potrzeby lokalnej maszyny. W praktyce oznacza to możliwość zamapowania na lokalny sinterfejs sieciowy **127.0.0.X** dowolnego nagłówka hosta. W rzeczywistości wykorzystuje się co najmniej dwie warstwy serwerów i tzw. **mechanizm reverse proxy**, w którym ruch trafia do warstwy serwerów frontowych na portach 80/443, a stamtąd do serwerów backendowych, schowanych wewnątrz sieci dostawcy. ### 2.4 Formularz, HTTP POST Komunikacja zwrotna klienta z serwerem możliwa jest dzięki **formularzom** > Np.: > ```html > <!DOCTYPE html> > <html lang="en"> > <head> > <meta charset="UTF-8"> > <meta name="viewport" content="width=device-width, initial-scale=1.0"> > <meta http-equiv="X-UA-Compatible" content="ie=edge"> > <title>Document</title> > </head> > <body> > <form method="POST" enctype="application/x-www-form-urlencoded"> > <div> > Login: <input type='text' name='login' /><br/> > <button>Login</button> > </div> > </form> > </body> > </html> > ``` # Wykład 8 ## 1. Express Najpopularniejszy i najprzystępniejszy framework do wytwarzania w node.js aplikacji niternetowych opartych o klasyczny schemat **Request-Reply**. Inne podejście - **Single-Page Applications**, gdzie strony nie przeładowują się z każdą interakcją użytkownika (React/Angular) ## 2. Middleware Funkcja, która obsługuje żądanie i która może delegować częśc pracy do kolejnej funkcji typu middleware. Obsługa żądania może tworzyć łańcuch wywołań: ![image](https://hackmd.io/_uploads/rka42GWs6.png) Celem tego jest rozdzielenie obsługi autentykacji od obsługi renderowania od obsługi błędów itp. DO obsługi błędów służy przeciążenie funkcji middleware **z czterema argumentami**. Poniżej przykład, gdzie przekazanie błędu wymaga przekazania jednego paramteru do **next**: ```javascript= var http = require('http'); var express = require('express'); var app = express(); app.use( (req, res, next) => { if ( true ) //warunek błędu next('describtion'); else res.end('poprawne działanie'); }); app.use( (errm req, res, next) => { res.end( `Error handling request: ${err}`); }); http.createServer(app).listen(3000); ``` ## 3. EJS (Embedded Javascript) Jeden z wielu silników renderowania dla Express. Zwalnia on z konieczności ręcznego zarządzania szablonami "stron". Wymaga foldera, w którym zapisane są widoki. Sprawia to, że silnik szablonów jest niezależny od silnika aplikacji. Konfiguruje się to w ten sposób: - Konfiguracja silnika renderowania - parametr **view engine** - Konfiguarcja lokalizacji z widokami - parametr **views** > ```javascript > //... > var app = express(); > app.set('view engine', 'ejs'); > app.set('views', './views'); > //... > ``` Domyślne rozszerzenie stron **(.ejs)** można zmienić na **.html** z dodatkową prostą konfiguracją ```javascript app.engine('html', ejs.renderFile); app.set('view engine', 'html'); ``` Najważniejszą cechą EJS jest możliwość mieszania elementów deklaratywnych i imperatywnych wewnątrz widoków, w tym m.in. deklarowanie zmiennych lokalnych - **<%** i **%>** - ograniczniki struktury imperatywnej - **<%=** i **%>** - umożliwiają wypisanie wartości - **<%-** i **%>** - wypisanie wartości zakodowanej (tzw. HTML encoding) ```html <% var foo = 'bar' %> <% for ( var i=0; i<5; i++ ) { %> <div> Element <%= i %> </div> <% } %> Zmienna foo: <%= foo %> ``` ## 4. Dodatkowe elementy architektury aplikacji ### 4.1 Middleware do plików statycznych Middleware **epxress.static** pozwala określić folder, z którego serwowane są pliki statyczne - w strukturze plików aplikacji jest to zwykle podfolder, ale z punktu widzenia http adresowanie jest względne do roota aplikacji. ### 4.2 Kontrola typu zwracanej odpowiedzi Za pomocą ustawiania nagłówków możliwe jest kontrolowanie typu odpowiedzi (np. wymuszenie potraktowania odpowiedzi jako pliku do pobrania możliwe jest za pomocą nagłówka Content-disposition) ### 4.3 Obsługa nawigacji między "stronami" Do przekierowania żądania do innego adresu służy metoda **redirect** obiektu odpowiedzi. Serwer odsyła do przeglądarki status **302 Object moved** z nagłówkiem Location wskazującym na nowy adres. Przeglądarka sama udaje się pod nowy adres z żądaniem typu **GET** ![image](https://hackmd.io/_uploads/ByaNtXWsT.png) ### 4.4 Odczytywanie parametrów przekazanych w pasku adresowym Odczyt parametrów przekazanych w pasku adresowym możliwy jest za pomocą właściwości **query** obiektu żądania. ### 4.5 Ścieżki dla żądań różnego typu (GET/POST) Express umożliwia powiązanie funkcji middleware z typem żądania (GET/POST). Zwyczajowo używa się tego do odróżnienia pierwszego żądania, które renderuje zawartość (GET) od kolejnych, które obsługują zwrotnie odesłany formularz (POST) Odczyt danych z formularza (POST) wymaga dodatkowego middleware, **express.urlencoded**. # Wykład 9 ### Domyślne middleware do obsługi nieobsłużonych ścieżek oraz zagrożenie Cross-Site Scripting "Domyślne" middleware, dodane jako ostatnie, będzie obsługiwać wszystkie nieobsłużone do tej pory ścieżki. Użycie znacznika **<%= i %>** chroni aplikację przed zagrożeniem (typu atak polagający na przesłaniu przez atakującego spreparowanego odnośnika zawierającego fragment skryptu do wykonania, np: **http://localhost:3000/foobar<script>window.alert(‘hello’)</script>**) ### Użycie parametrów w ścieżkach i zagrożenie Web Parameter Tampering Możliwe jest dynamiczne parametryzowanie ścieżek. Sparametryzowana ścieżka dospwuje się do całej klasy ścieżek, a ograniczenie dopasowania polega na możliwości użycia wyrażenia regularnego, (na przykład wymuszającego tylko liczby). Jednym z typowych mechanizmów ochrony przed tym zagrożeniem jest użycie dodatkowego parametru weryfikującego poprawność odnośnika, wykorzystującego mechanizm HMAC (Hash Message Authentication Code)/ Na serwerze parametr ścieżki adresowej jest łączony z **kluczem tajnym** a otrzymana wartość jest używa jako argument do jednokierunkowej funkcji skrótu. Wynik jest dodawany do adresu jako jego "podpis", a niezgodność podpisu wyliczonego z oczekiwanym oznacza, że użytkownik **zmodyfikował** wartość parametru. _____ Inny, prostszy ale nie zawsze możliwy sposób ochrony przed tym zagrożeniem pojawia się gdy link dotyczy **zalogowanego użytkownika** (który na przykład dostał dane z bazy danych powiązanych jakoś ze swoimi danymi). Czyli - jest zapytanie, które dla zalogowanego użytkownika zwraca listę dozwolonych identyfikatorów i ona pojawia się jako część listy odnośników. Zatem sprwadzane są warunki: - użytkownik niezalogowany - zwracana informacja o błędzie - użytkownik zalogowany - zapytanie wyciągające zbiór identyfiaktorów jest powtarzane a nasepnie sprawdza się czy przychodząca wartość parametru znajduje się w zbiorze: - nie znajduje się - zwracana informacja o błędzie - znajduje się - zwracamy dane ## Obsługa ciasteczek Używa się middleware **cookie-parser**. # Wykład 13 ## 1. Trochę SQLa ### 1.1 SELECT * Do pobrania danych z tabeli służy zapytanie typu `SELECT` ```sql= SELECT * from Parent ``` * Zbiór wynikowy może być dodatkowo ograniczony klauzulą `WHERE` ```sql= SELECT * from Parent WHERE ParentName='parent1' ``` * Klauzul może być wiele i mogą tworzyć całe wyrażenie logiczne, tutaj wybieramy wszystkie wiersze leżące pomiędzy tymi dwoma ```sql= SELECT * from Parent WHERE 'parent'<ParentName AND ParentName<'parent1' ``` * Zbiór może być dodatkowo uporządkowany za pomocą `ORDER BY` ```sql= SELECT * from Parent WHERE 'parent'<ParentName AND ParentName<'parent1' ORDER BY ParentName ``` ## 1.2 INSERT Dodawanie danych do tabeli możliwe jest za pomocą zapytania typu `INSERT`. * To zapytanie wstawia nowy wiersz do tabeli Parent i przypisuje wartość 'Parent1' do kolumny ParentName ```sql= INSERT INTO Parent (ParentName) VALUES ('Parent1') ``` Z kolei w sytuacji gdy jako generator wartości klucza głównego służy sekwencja mamy: ```sql= CREATE SEQUENCE sequence_name START WITH 1 INCREMENT BY 1; ``` * Wstawianie rekordów z użyciem sekwencji ```sql= INSERT INTO Parent (Imie, Nazwisko, Plec) VALUES ('Jan', 'Kowalski', 'M'); ``` ## 1.3 UPDATE/DELETE * Do modyfikacji rekordów służy zapytanie typu UPDATE np. ```sql= UPDATE Parent SET ParentName='new name' WHERE ID=1 ``` * Do usuwania rekordów – DELETE ```sql= DELETE FROM Parent WHERE ID=1 ``` #TODO

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully