class: center, middle # ES2015+ features ## běžně používané ve FlowUpu --- # ECMAScript/JavaScript/TypeScript ## ECMAScript - standardizovaná specifikace JavaScriptu (standard ECMA-262) - edice: 1. ES1 (1997) 2. ES2 (1998) 3. ES3 (1999) 4. ES5 (2009) 5. ES5.1 (2011) 6. ES2015 (dříve a populárně/nekorektně ES6) 7. ES2016 8. ES2017 9. *ESNext* ## TypeScript - nadmnožina JS (rozšíření o statické typování) kompilovaná do JS vyvíjená Microsoftem --- # Lokální proměnné ## `var` - *function-scope* ‐ platnost od začátku do konce funkce **bez ohledu na pozici deklarace** - **nepoužívat!** ## `const` a `let` (ES2015+) - *block-scope* ‐ platnost od deklarace do konce bloku - `const` proměnná - musí být inicializovaná při deklaraci - nesmí být změněna její hodnota - ...ale může být mutován objekt, reference na nějž je její hodnotou ```javascript const user = {name: 'Michael Scott'}; user.name = 'Jan Levinson'; // OK user = {name: 'Jim Halpert'}; // TypeError: Assignment to constant variable ``` --- # Omezení mutace proměnných (1/3) ## Podmíněné přiřazení ```javascript let personality; if (glassHalfFull) { personality = 'optimist'; } else { personality = 'pessimist'; } ``` .centered[.rotated[»]] ```javascript const personality = glassHalfFull ? 'optimist' : 'pessimist'; ``` --- # Omezení mutace proměnných (2/3) ## Sanitizace hodnoty ```javascript function factorial(x) { x = Math.max(x, 0); x = Math.floor(x); return x > 0 ? x * factorial(x - 1) : 1; } ``` .centered[.rotated[»]] ```javascript function factorial(x) { const nonNegativeX = Math.max(x, 0); const naturalX = Math.floor(nonNegativeX); return naturalX > 0 ? naturalX * factorial(naturalX - 1) : 1; } ``` --- # Omezení mutace proměnných (3/3) ## Agregace ```javascript const values = [6654, 1896, 6545, 1235, 7676]; let sum = 0; for (const value of values) { sum += value; } ``` .centered[.rotated[»]] ```javascript const values = [6654, 1896, 6545, 1235, 7676]; const sum = values.reduce((acc, value) => acc + value); ``` --- # Template-literály - ohraničené zpětnými úvozovkami - výrazy uzavřené v `${ }` se vyhodnotí, stringifikují a vloží do výsledného stringu - můžou obsahovat fyzické odřádkování; **vloží ho do výsledného stringu** - lze je vnořovat - použitelné i pro stručný zápis typové konverze do stringu ```javascript const user = {firstName: 'Lee', lastName: 'Mack', email: 'jon@doe.io', phone: '123456789'}; const userName = user.firstName + ' ' + user.lastName; const userSummary = userName + ', ' + (user.phone ? 'tel: ' + user.phone : user.email); const screenWidth = String(window.innerWidth); ``` .centered[.rotated[≈]] ```javascript const user = {firstName: 'Lee', lastName: 'Mack', email: 'jon@doe.io', phone: '123456789'}; const userName = `${user.firstName} ${user.lastName}`; const userSummary = `${userName}, ${user.phone ? `tel: ${user.phone}` : user.email}`; const screenWidth = `${window.innerWidth}`; ``` --- # Generování klíčů v obj. literálech ## Inference z identifikátorů ```javascript const firstName = 'Marcel', lastName = 'Čučoriedka'; const user = {firstName, lastName, age: 42}; // {firstName: 'Marcel', lastName: 'Čučoriedka', age: 42} ``` ## Dynamická kalkulace ```javascript const key = 'foo', value = 'bar'; const withoutBrackets = {key: value}; // {key: 'bar'} const withBrackets = {[key]: value}; // {foo: 'bar'} ``` --- # Array-spread ## Příklad ```javascript const numbers = [1, 2, 3], letters = ['a', 'b', 'c']; const b = [...numbers, true, ...letters, false]; // [1, 2, 3, true, 'a', 'b', 'c', false] ``` ## Využití ```javascript const result = [...array1, ...array2, ...array3]; // konkatenace let stack = []; stack = [...stack, someValue]; // "imutabilní push" const copy = [...original]; // kopie ``` --- # Object-spread *(ESNext)* ## Příklad ```javascript const size = {width: '20px', height: '40px'}; const color = {red: 63, green: 127, blue: 255}; const colorPatch = {green: 31, blue: 191}; const shape = {...color, ...size, blue: 0, ...colorPatch, height: '60px'}; // {width: '20px', height: '60px', red: 63, green: 31, blue: 191} ``` ## Využití ```javascript const maleAges = {evzen: 25, alfonz: 54}, femaleAges = {yolanda: 32}; let allAges = {...maleAges, ...femaleAges}; // sjednocení allAges = {...allAges, herbert: 31}; // "create" allAges = {...allAges, evzen: 26} // "update" allAges = {evzen: 27, ...allAges}; // "create" podmíněný neexistencí allAges = {...allAges, ...includeGertruda && {gertruda: 58}}; // "create" podmíněný výrazem ``` --- # Argument-spread ## Příklad ```javascript const someValues = [1, 8, 4, 5, 2]; const maximum = Math.max(...someValues); // ≈ Math.max(1, 8, 4, 5, 2); ``` --- # Parametry ## Implicitní hodnoty parametrů ```javascript function toPercent(value, sign = '%') { return `${value * 100}${sign}`; } ``` ## Rest-parametry ```javascript function pickRandom(randomSign, ...numbers) { const sign = randomSign ? Math.sign(Math.random() - 0.5) : 1; const index = Math.floor(Math.random() * numbers.length); return sign * numbers[index]; } const random = pickRandom(true, 2, 3, 5); // random ∈ {-5, -3, -2, 2, 3, 5} ``` --- # Destrukturace polí ## Do proměnných ```javascript const places = 'Alice > Bob > Claudia > David > Elizabeth'; const [gold, silver, bronze, ...noOneCares] = places.split(' > '); const [safety = 42, is = 34, everything = 0] = arrayOrNull || []; ``` ## Do parametrů ```javascript function magnitude([x, y]) { return (x ** 2 + y ** 2) ** 0.5; } const vector = [3, 4]; const vectorMagnitude = magnitude(v); // 5 ``` --- # Destrukturace objektů ```javascript const myObject = {hello: 'world', foo: 'bar', flow: 'up', java: 'script'}; const {hello, yolo, foo = 'bang', yin = 'yang'} = myObject; // console.log(hello, yolo, foo, yin); --> world undefined bar yang ``` ## Využití - nižší verbozita kódu (užitečné hlavně v delších výrazech) - simulace pojmenovaných nepozičních argumentů *a la Python* ```javascript function someFunc(pos1, pos2, {named1, named2, named3} = {}) { } someFunc('foo', 42, {named3: 34, named1: 'foo'}); ``` - "imutabilní `delete`" ```javascript const bandAlbums = {slipknot: 5, nirvana: 3, billyTalent: 5}; const {nirvana, ...activeBandAlbums} = bandAlbums; ``` --- # Arrow funkce - zkrácený zápis *funkčních výrazů (function expressions)* s lexikální vazbou na `this` - tělem je blok nebo výraz ```javascript const cylinderVolume = function(radius, height) { const baseArea = Math.PI * radius ** 2; return baseArea * height; } ``` .centered[.rotated[≈]] ```javascript const cylinderVolume = (radius, height) => { const baseArea = Math.PI * radius ** 2; return baseArea * height; } ``` .centered[.rotated[≈]] ```javascript const cylinderVolume = (radius, height) => Math.PI * radius ** 2 * height; ``` --- # Lexikální vazba `=>` na `this` - `this` uvnitř arrow funkce odpovídá `this` ve vnějším lexikálním kontextu ```javascript const outer = { name: 'Outer object', test: function() { const inner = { name: 'Inner object', printThisNormal: function() { console.log(`normal: ${this.name}`); }, printThisArrow: () => { console.log(`arrow: ${this.name}`); } }; inner.printThisNormal(); inner.printThisArrow(); } }; outer.test(); // normal: Inner object // arrow: Outer object ``` --- # Díky za pozornost! ## It's-a-me, Mario! - pavel.tobias@flowup.cz - **@pavel** na Slacku ## Zdroje: - MDN Web Docs (https://developer.mozilla.org) - ECMAScript 6: New Features: Overview and Comparison (http://es6-features.org) - naše codebase a zkušenosti ;-)