Warsztaty JavaScript

JavaScript Developer @ Evojam

@RobertDuraj

rduraj@gmail.com

Robert Duraj

http://bit.ly/js-lingua-franca

Cel: Facebook 2.0

  • Teoria vs Praktyka
  • Iteracyjne zdobywanie wiedzy
  • Ciągły refactoring
  • Prosto do działającego projektu!

Agenda

  • Sekcja #1:
    • API (server, przeglądarka)
    • Środowisko testowe (projekt startowy)
    • Twoje pierwsze "Hello World"
  • QnA
  • TODO

Agenda

  • Sekcja #2:
    • Idea komponentu (CDD)
    • zmienne, stałe
    • funkcje
  • QnA
  • TODO

Agenda

  • Sekcja #3:
    • instrukcje warunkowe
    • obiekty i tablice
    • pętle
  • QnA
  • TODO

Agenda

  • Sekcja #4:
    • zdarzenia
    • nasłuchiwanie na zdarzenia
  • QnA
  • TODO

Agenda

  • Sekcja #5:
    • EcmaScript 5 - 2018
  • QnA
  • TODO

Agenda

  • Sekcja #6:
    • LocalStorage
    • SessionStorage
    • Cookies
  • QnA
  • TODO

Agenda

  • Sekcja #7:
    • Komunikacja z API aplikacji
    • Callbacks
    • Promises
  • QnA
  • TODO

Agenda

  • Sekcja #8:
    • Konteksty
    • Prototypy
  • QnA
  • TODO

Sekcja #1

API

Application Programming Interface

  • przeglądarki
  • aplikacji
  • klasy
  • urządzenia
  • etc.

Projekt startowy:

 

  • http://bit.ly/js-workshop-template
<!DOCTYPE html>
<html>
<head>
    <link rel="stylesheet" type="text/css" href="./styles/app.css" />
</head>
<body>
    <header>
        <h1>My FB</h1>
    </header>
    <main>
        <p>FB content</p>
    </main>

    <footer>© JS workshops 2018</footer>
</body>
</html>

Jak zacząć pracę z JS?

Jak zacząć pracę z JS?

<!DOCTYPE html>
<html>
<head>
    <link rel="stylesheet" type="text/css" href="./styles/app.css" />
</head>
<body>
    <header>
        <h1>My FB</h1>
    </header>
    <main>
        <p>FB content</p>
    </main>

    <footer>© JS workshops 2018</footer>
    <script src="./scripts/app.js" />
</body>
</html>
<script src="./scripts/app.js" />
<script>

// JS code here

</script>

Praca z API Twojej przeglądarki

// ./scripts/app.js


window.alert("Hello Bielsko!")
// ./scripts/app.js

console.log(window);

Dev tools API

// ./scripts/app.js

window.console.log(window);

QnA

TODO:

  1. Stwórz w projekcie plik ./scripts/app.js
  2. Załaduj w index.html, przed zakończeniem taga <body> skrypt JS: ./scripts/app.js
  3. Napisz prosty skrypt (w dołączonym wcześniej pliku), wyświetlający Twoje imię w przeglądarce, korzystając z metody alert(...)
  4. Zamień metodę alert() na prompt() i zobacz, czym różnią się obie te metody.

Sekcja #2

CDD

Component

Driven

Development

HTML-based templates

<div class="card">
    <h5><time>17.05.2018</time> - Bob Dylan</h5>
    <p>Knockin' On Heaven's Door...</p>
</div>
<script type="text/template" id="message-template">
    <div class="card">
        <h5><time>{{date}}</time> - {{author}}</h5>
        <p>{{message}}</p>
    </div>
</script>
<script type="text/template" id="message-template">
    <div class="card">
        <h5><time>17.05.2018</time> - Bob Dylan</h5>
        <p>Knockin' On Heaven's Door...</p>
    </div>
</script>

Jak pracować z szablonem?

// ./scripts/app.js

window.document.getElementById('message-template');
// ./scripts/app.js

console.log(window.document.getElementById('message-template').innerHTML);

Przypisanie do zmiennej

// ./scripts/app.js

const templateElement = window.document.getElementById('message-template');

console.log(templateElement.innerHTML);
// ./scripts/app.js

const getTemplateById = window.document.getElementById;

console.log(getTemplateById('message-template').innerHTML);

Operatory przypisania i typy

// ./scripts/app.js

let A = 'jakiś string';

//...

A = 4;

console.log(A); // 4
// ./scripts/app.js

const A = 'jakiś string';
const B = ' z dopiskiem';
const C = 5;

console.log(A + B); // 'jakiś string z dopiskiem';
console.log(A + B + C); // 'jakiś string z dopiskiem5';

Operatory przypisania i typy

// ./scripts/app.js

let A = 'Hello ';
A += 'World'; // A = A + 'World';
// ./scripts/app.js

const A = 'jakiś string';
const B = ' z dopiskiem';

console.log(B - A); // NaN

const C = '2';
const D = '1';

console.log(C - D); // 1

Tworzenie funkcji - function, return

// ./scripts/app.js

const templateElement = window.document.getElementById('message-template');

console.log(templateElement.innerHTML);
// ./scripts/app.js

function getTemplateByName(name) {
    var templateId = name + '-template';
    var templateElement = window.document.getElementById(templateId);
    return templateElement.innerHTML;
}

const template = getTemplateByName('message');
// ./scripts/app.js

const getTemplateByName = function(name) {
   return window.document.getElementById(name + '-template').innerHTML;
}

const template = getTemplateByName('message');

Czym jest zasięg widoczności zmiennej?

const A = 'stała o zasięgu globalnym';

function test() {
    console.log(A); // stała o zasięgu globalnym

    const B = 'stała o zasięgu funkcji';
    var C = 'zmienna var o zasięgu funkcji';

    if (true === true) {
        console.log(A); // stała o zasięgu globalnym
        console.log(B); // stała o zasięgu funkcji
        console.log(C); // 'zmienna var o zasięgu funkcji'
        let D = 'zmienna let o zasięgu klamry';
    }

    console.log(B); // stała o zasięgu funkcji
    console.log(C); // 'zmienna var o zasięgu funkcji'
    console.log(D); // udefined
}

test();

console.log(A); // stała o zasięgu globalnym
console.log(B); // udefined
console.log(C); // udefined
console.log(D); // udefined

var, let, const - zatem kiedy?!

CONST

QnA

TODO:

  1. Stwórz template dla pojedynczej wiadomości w pliku index.html
  2. W pliku ./scripts/app.js stwórz metodę getTemplateByName do pobierania template'ów po nazwie, przetestuj na szablonie wiadomości z #1
  3. Skorzystaj z utworzonej funkcji getTemplateByName i dodaj pobrany szablon do obiektu #list korzystając z metod getElementById i właściwości innerHTML

Sekcja #3

Instrukcje warunkowe - If, else, switch

// ./scripts/app.js

if (...warunek) {
  // then
} else {
  // then
} 
// ./scripts/app.js

if ('5' === 5) {
  console.log('A')
} else {
  console.log('B');
} 
// ./scripts/app.js

switch (letter) {
   case 'A':
    console.log('A jak Ala!');
    break;
   case 'B':
    console.log('B jak BMW!');
    break;
   default:
    console.log('Każda inna litera też jest fajna!');
}

Obiekty i tablice

Obiekty

// ./scripts/app.js

const dog = {
    name: 'Frodo',
    bark: function () {
        console.log('woof! woof!');
    }
};

console.log(dog); // { name: 'Frodo', bark: f }
console.log(dog.name); // Frodo
console.log(dog.bark()); // woof! woof!
// ./scripts/app.js

const oldHello = "Hello World";
const betterHello = oldHello.replace('World', 'Bielsko');

console.log(oldHello); // "Hello World"
console.log(betterHello); // "Hello Bielsko"

Tablice

// ./scripts/app.js

const messages = [];
// ./scripts/app.js

const messages = [];

console.log(typeof messages); // "object"
// ./scripts/app.js

const messages = [1, 2, 3, 4];

messages.push(5);
console.log(messages); // [1, 2, 3, 4, 5];

messages.pop();
console.log(messages); // [1, 2, 3, 4];

messages.shift();
console.log(messages); // [2, 3, 4];

Pętle

// ./scripts/app.js

const messages = [
    { name: 'Bob Dylan', message: 'Like a Rolling Stone...' },
    { name: 'Batman', message: 'I am Batman!' },
];
// ./scripts/app.js

for (let index = 0; index < messages.length; index++) {
   console.log(messages[index]); // { name: ..., message: ... };
}
// ./scripts/app.js

messages.forEach(function(message) {
    console.log(message); // { name: ..., message: ... };
});

TODO:

Z podanej tablicy quotes, za pomocą pętli, stwórz listę bohaterów Władcy Pierścieni, pomijając osoby, które nie wystąpiły w książce...

const quotes = [
    { 
        name: 'Lady Galadriel', 
        quote: 'Even the smallest person can change the course of history.',
    },
    { 
        name: 'Frodo', 
        quote: 'It is useless to meet revenge with revenge: it will heal nothing.',
    },
    { 
        name: 'Yoda', 
        quote: 'Do or do not. There is no try',
    },
]

map & filter

// ./scripts/app.js

const messages = [
    { name: 'Bob Dylan', message: 'Like a Rolling Stone...' },
    { name: 'Batman', message: 'I am Batman!' },
];
// ./scripts/app.js

const authors = messages.map(function(message) {
    return message.name;
});

console.log(authors); // ['Bob Dylan', 'Batman'];
// ./scripts/app.js

const batmanMessages = messages.filter(function(message) {
    return message.name === 'Batman';
});

console.log(batmanMessages); // [{ name: 'Batman', message: 'I am Batman!' }];

TODO:

Zamień poprzednio utworzoną pętlę na połączone metody filter i map, wykonując to samo zadanie:

const quotes = [
    { 
        name: 'Lady Galadriel', 
        quote: 'Even the smallest person can change the course of history.',
    },
    { 
        name: 'Frodo', 
        quote: 'It is useless to meet revenge with revenge: it will heal nothing.',
    },
    { 
        name: 'Yoda', 
        quote: 'Do or do not. There is no try',
    },
]

reduce

const numbers = [1, 2, 3, 5, 7, 3];
numbers.reduce(function(accumulate, current) {
    return accumulate + current;
}, 0); 

// 21
const messages = [
    { name: 'Bob Dylan', message: 'Like a Rolling Stone...' },
    { name: 'Batman', message: 'I am Batman!' },
];

messages.reduce(function(acc, cur) {
    return acc + cur.name + ' ';
}, '');
messages
    .map(function(message) { 
        return message.name;
    })
    .join(', ');

QnA

TODO:

  1. Stwórz tablicę messages
  2. Dodaj do niej dwa obiekty, zawierające pola name oraz message
  3. Stwórz metodę createMessage, która będzie oczekiwać dwóch argumentów: name i message
  4. W metodzie createMessage pobierz szblon wcześniej utworzoną metodą (getTemplateByName) i korzystastając z metody (String).replace, zamień {{name}} i {{message}} na argumenty funkcji (name i message)

TODO:

  1. Zmapuj tablicę messages, tak, żeby zawierała szablony wiadomości stworzone przez createMessage
  2. Dodaj każdy kolejny element zmapowanej tablicy messages do obiektu #list wyświetlając wszystkie elementy na widoku.

Powtórka

Zmienne, stałe

const A = 'stała A'
const numberA = 5

let B = 'zmienna B'
let numberB = 5


console.log(A) // 'stała A'
console.log(numberA) // 5
console.log(B) // 'zmienna A'
console.log(numberB) // 5

B = 'zmienna zmieniona B'
console.log(B) // 'zmienna zmieniona B'

Operatory arytmetyczne

console.log(5+5); // 10

const A = 5;
const B = 5;

console.log(A+B) // 10
console.log(A-B) // 0
console.log(A/B) // 1
console.log(A*B) // 25
console.log(A%B) // 0


const stringA = 'Ala ma ';
const stringB = 'kota';

console.log(stringA + stringB); // 'Ala ma kota'

Funkcje

function nazwaFunkcji (argument1, argument2, argument3) {

    console.log(argument1, argument2, argument3);

}


nazwaFunkcji('A', 'B', 5); // 'A' 'B' 5

Obiekty

const jedi = {
    
    imie: 'Yoda',
    usePower: function () {
        console.log('Mmmm, do or do not, there is no try');
    }

}
function Jedi () {
    this.imie = 'Yoda';

    this.useForce = function () {
        console.log('Mmm. Do or do not, there is no try');
    }
}

const Yoda = new Jedi();
Yoda.useForce();

Tablice

const tablica = [];


tablica.push('A');
console.log(tablica); // ['A'];


tablica.push('B');
tablica.shift();
console.log(tablica) // ['B']

Pętla forEach

const tablica = ['Ala', 'ma', 'kota']


tablica.forEach(function(slowo) {
    console.log(slowo.toUpperCase());
})                                    // 'ALA' 'MA' 'KOTA'

http://bit.ly/js-workshop-template-2

Sekcja #4

Zdarzenia w DOM

Zdarzenie kliknięcia

<button onClick="alert('Hello World');">Przywitaj się!</button>
// ./scripts/app.js

document.getElementById('hello-button').addEventListener('click', function() {
    alert('Hello World!');
});
<button id="hello-button">Przywitaj się!</button>

Popularne eventy:

  • onChange
  • onClick
  • onMouseOver
  • onMouseOut
  • onKeyDown
  • onLoad
  • focus
  • blur

QnA

TODO:

  1. Dodaj ID do przycisku wyślij w formularzu wiadomości
  2. Przechwyć za pomocą listenera moment kliknięcia w button
  3. Pobierz wartość pola textarea za pomocą wartości .value na elemencie textarea i zapisz ją do zmiennej
  4. Utwórz wiadomość za pomocą createMessage i dodaj ją do listy.

Sekcja #5

Arrow functions

() => {}  
/*
 function() {}
*/


value => value 
/*
 function(value) { return value; }
*/


() => ({ field: 'value' })
/*
 function() { 
    return {
        field: 'value',
    }
 }
*/
const getTemplateByName = name => window
    .document
    .getElementById(name + '-template')
    .innerHTML;

Destructuring objects

function logUser(user) {
   console.log(user.firstName, user.lastName, user.email);
}
function logUser({ firstName, lastName, email }) {
   console.log(firstName, lastName, email);
}
function logArray(array) {
    console.log(array[0], array[1]);
}

logArray(['firstElement', 'secondElement']); // 'firstElement', 'secondElement'
function logArray([firstElement, secondElement]) {
    console.log(firstElement, secondElement);
}

logArray(['firstElement', 'secondElement']); // 'firstElement', 'secondElement'

Spread operator / rest parameters (...)

function logArguments() {
    console.log(arguments);
}

logArguments('A', 'B', 'C'); // Arguments: ['A', 'B', 'C']
function logArguments(firstArgument, ...rest) {
    console.log(firstArgument, rest);
}

logArguments('A', 'B', 'C'); // Arguments: 'A', ['B', 'C']

class

class A {

 constructor() {
    this.AField = 'A';
 }

 showA() {
   console.log(this.AField);
 }

}


class B extends A {

  constructor() {
    super()

    this.BField = 'B';
  }

  showAB() {
    console.log(this.AField, this.BField);
  }
}


const AB = new B();
AB.showAB();

Default function parameters

function showMessage(message, author) {
    if (author === undefined) {
        author = 'Anonymous';
    }

    return '"'message + '" by ' + author;
}
function showMessage(message, author = 'Anonymous') {

    return '"'message + '" by ' + author;
}

Template Literals

const owner = 'Ala';

const oldFashionTemplate = 'Mała ' + owner + ' ma kota';

const withTemplateLiterals = `Mała ${owner} ma kota`;
function showMessage(message, author = 'Anonymous') {

    return `"${message}" by ${author}`;
}

QnA

TODO:

  1. Zrefaktoryzuj dotychczasowy kod, korzystając z możliwości jakie oferuje nowa specyfikacja EcmaScript
  2. Postaraj się wykorzystać jak najwięcej nowych elementów
  3. Wykorzystaj np. arrow functions do skrócenia zapisu .map

Sekcja #6

Dostęp do localStorage

window.localStorage.setItem('key', value);
window.localStorage.getItem('key');
window.localStorage.removeItem('key');

Obiekty w localStorage

window.localStorage.setItem(
    'messages', 
    JSON.stringify([{ message: 'text', author: 'Bob Dylan']),
);
const messages = JSON.parse(localStorage.getItem('messages'));

Dostęp do sessionStorage

window.sessionStorage.setItem('key', value);
window.sessionStorage.getItem('key');
window.sessionStorage.removeItem('key');

Dostęp do cookies

document.cookie = "yummy_cookie=choco"; 
document.cookie = "tasty_cookie=strawberry"; 
console.log(document.cookie); 

// logs "yummy_cookie=choco; tasty_cookie=strawberry"
const d = new Date();
d.setTime(d.getTime() + 5*1000); // in milliseconds
document.cookie = 'foo=bar;path=/;expires='+d.toGMTString()+';';

QnA

TODO:

  1. Zapisz każdą nową dodaną wiadomość do localStorage
  2. Po załadowaniu skryptu, odczytaj wszystkie wiadomości z localStorage i wyświetl na stronie

Sekcja #7

TBC

Sekcja #8

TBC

JS Workshops

By Robert

JS Workshops

  • 293