Modern JavaScript (since ES6 Harmony) Martin Kruliš by Martin Kruliš (v1.1) 18. 4. 2019
ECMA Script Evolution Recent Rapid Development Browser Compatibility Finalized in June 2015 Many significant changes But backwards compatible with ES 5 ECMAScript 7 (2016) ECMAScript 8 (2017) ECMAScript 9 (2018) Browser Compatibility Nearly 100% support of ES 6 in newest browsers Careful with older browsers (LTS systems, IE 11, …) by Martin Kruliš (v1.1) 18. 4. 2019
ECMA Script 6 Block Scope Block scope variables declared by let (instead of var) for (let i = 0; i < 10; ++i) … Function declarations are block-scoped as well function foo () { return 1; } foo(); // returns 1 { function foo () { return 2; } foo(); // returns 2 } by Martin Kruliš (v1.1) 18. 4. 2019
ECMA Script 6 Constants Constant (immutable) block-scoped variables const PI = 3.14; Only the variable is immutable Referenced object or array inside is mutable const obj = { foo: 42 }; const accumulator = []; obj.foo = 54; // OK accumulator.push(obj); // OK obj = { foo: 4254; } // not OK !!! A good hint for JS engine (garbage collector) by Martin Kruliš (v1.1) 18. 4. 2019
ECMA Script 6 Template Literals Extended Literals Similar to PHP interpreted (double-quoted) strings let amount = 42; let cost = 54; // per capita let str = `Total ${amount} items for ${amount * cost}`; Extended Literals Binary literals 0b00101010 Octal literals 0o52 Back apostrophes by Martin Kruliš (v1.1) 18. 4. 2019
ECMA Script 6 Classes A concept of “real” classes introduced class Square { constructor(side) { this.side = side; } function Suqare(side) { var square = new Square(42); New ES6 syntax for creating classes In fact, it creates constructing function (as in ES5) In both cases, objects are created by new operator by Martin Kruliš (v1.1) 18. 4. 2019
ECMA Script 6 Classes A sugar code for prototyping class Circle extends GeometricShape { constructor(x, y, r) { super(x, y); this.r = r; } getArea() { return Math.PI * this.r * this.r; Inheritance implemented by prototyping Calling base class constructor Method (in fact a member of prototype) typeof Circle === 'function' typeof Circle.prototype === 'object' typeof Circle.prototype.getArea === 'function' by Martin Kruliš (v1.1) 18. 4. 2019
Getter and setter for a property ECMA Script 6 Classes Static methods, property getters/setters class Circle extends GeometricShape { static intersect(c1, c2) { ... } get diameter() { return 2 * this.r; } set diameter(d) { this.r = d / 2; Circle.intersect(...); c1.diameter = c2.diameter; Static method Getter and setter for a property by Martin Kruliš (v1.1) 18. 4. 2019
ECMA Script 6 Modules Way to export/import modular values without polluting the global context (avoiding name collisions) // mylib.js export function explain() { return "because 6 x 9"; }; export const universalConst = 42; // an application using mylib.js import * as mylib from "mylib"; console.log(mylib.universalConst + " " + mylib.explain()); // another application using mylib import { explain, universalConst } from "mylib"; console.log(universalConst + " " + explain()); by Martin Kruliš (v1.1) 18. 4. 2019
ECMA Script 6 Arrow Functions Simpler syntax for callback functions arr.map(function(x) { return x+1; }); // ES 5 arr.map(x => x+1) // ES 6 Lexical this Some differences, e.g., arrow function cannot be used as constructor var self = this; this.values.forEach( function(x){ if (x % 2 != 0) self.odds.push(x); } ); this.values.forEach( (x) => { if (x % 2 != 0) this.odds.push(x); } ); Arrow functions do not have their own this or arguments binding. Instead, those identifiers are resolved in the lexical scope like any other variable. That means that inside an arrow function, this and arguments refer to the values of this and arguments in the environment the arrow function is defined in (i.e., "outside" the arrow function). Arrow function “inherits” this from outer scope by Martin Kruliš (v1.1) 18. 4. 2019
ECMA Script 6 Extended Function Parameter Handling Default parameter values function inc(val, by = 1) { return val + by; } Aggregation of remaining arguments function merge(al, a2, ...restArrays) {} Spread collection elements as arguments var coords = [ 1, 2 ,3 ]; point.moveBy(...coords); // moveBy(1, 2, 3); var str = "bar"; var chars = [ "f", "o", "o", ...str ]; // b, a, r by Martin Kruliš (v1.1) 18. 4. 2019
ECMA Script 6 Destructing Assignments Array matching Object matching var list = [ 1, 2, 3 ]; var [ x, y, z ] = list; // var x=1, y=2, z=3 [ z, x, y ] = [ x, y, z ]; // rotate values x,y,z Object matching var { x, y, z } = get3Dpoint(); var { x: y, y: x, attrs: { depth: z } } = get2Dpoint(); Context argument matching function avgFirst2([a, b]) { return (a + b) / 2; } function distanceTo({x, y, z = 1}) { … } by Martin Kruliš (v1.1) 18. 4. 2019
ECMA Script 6 Promises Objects representing asynchronous action Also holds the result of the operation (data or error) Promises are replacing callback functions in APIs Two possible states Resolve – successfully completed, have data Reject – error occurred (thrown), have error message Highly combinable .then(), .catch(), .finally() Promise.all(), Promise.race() https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise by Martin Kruliš (v1.1) 18. 4. 2019
ECMA Script 6 Promises Example First a book record is fetched (containing author ID) Then author record is fetched fetch(`http://some.api/book/${id}`) .then(response => response.json()) .then(({ authorId }) => fetch(`http://some.api/users/${authorId}`)) .then(author => ...do something with autor...); by Martin Kruliš (v1.1) 18. 4. 2019
Traditional callbacks ECMA Script 6 Traditional callbacks Promises Example function ajaxGet(url, timeout, onData, onError) { … } function ajaxPromised(url, timeout) => { return new Promise((resolve, reject) => { ajaxGet(url, timeout, resolve, reject); }); } Promise.all([ ajaxPromised("http://my.domain/foo.php", 500), ajaxPromised("http://my.domain/bar.php", 500), ajaxPromised("http://my.domain/spam.php", 500), ]).then((data) => { let [ foo, bar, spam ] = data; showData(foo, bar, spam); }, (err) => { alert(err) } ); Wrapped in a promise Btw. It is not necessary to wrap AJAX queries like this since new fetch() API for HTTP requests was designed. The fetch() function automatically returns a promise object. by Martin Kruliš (v1.1) 18. 4. 2019
ECMA Script 6 Iterators let fibonacci = { [Symbol.iterator]() { let pre = 0, cur = 1; return { next () { [ pre, cur ] = [ cur, pre + cur ]; return { done:(cur > 1000), value:cur }; } }; for (let x of fibonacci) console.log(x); by Martin Kruliš (v1.1) 18. 4. 2019
Makes sure that complete property has value between 0 and 100 ECMA Script 6 Proxies let course = { name: "Advanced Technologies for Web Applications", complete: 53, // percent } let proxy = new Proxy(course, { set(target, property, value) { if (property != "complete") return true; return (value >= 0 && value <= 100); }); Makes sure that complete property has value between 0 and 100 by Martin Kruliš (v1.1) 18. 4. 2019
ECMA Script 6 New Data Structures Set – a collection of unique items const s = new Set(); s.add("kitten").add("hippo").add("kitten"); s.size; // === 3 s.has("hippo"); // === true Map – a dictionary (key-value) structure const m = new Map(); m.set("answer", 42); m.set("correct", 54); m.get("correct"); // === 54 m.size; // === 2 by Martin Kruliš (v1.1) 18. 4. 2019
Functional Approach Shift in Paradigm JavaScript is leaning steadily towards functional programming paradigm const data = [ 1, 2, 3, 4, 5, 6 ]; for (let i = 0; i < data.length; ++i) { if (data[i] % 2 !== 0) continue; let x = data[i] * data[i]; console.log(x); } Prints out 4, 16, and 36 by Martin Kruliš (v1.1) 18. 4. 2019
Functional Approach Shift in Paradigm JavaScript is leaning steadily towards functional programming paradigm const data = [ 1, 2, 3, 4, 5, 6 ]; data.filter(x => x % 2 === 0) .map(x => x * x) .forEach(x => console.log(x)); Yields [2, 4, 6] Yields [4, 16, 36] Prints out 4, 16, and 36 by Martin Kruliš (v1.1) 18. 4. 2019
Functional Approach JavaScript Support Methods for functional array processing Already there since ES5 Streamline function declarations Arrow functions introduced Many semantic constructions may be expressions With a little help from && and || operators They do not return bool value, but the value of the first operand that renders the expression false or the value of last operand var x = struct && struct.nest && struct.nest.foo; by Martin Kruliš (v1.1) 18. 4. 2019
Immutability Immutability Concept Data cannot be changed New copy of (modified) data can be created Pure functions Only read inputs, no side effects Reasons Efficiency, parallelization Auto-caching functions (compute-memory tradeoff) Versioning (keeping history, replaying events) by Martin Kruliš (v1.1) 18. 4. 2019
Immutability Immutability Issues Solution Hard to enforce, hard to detect const obj = { foo: 42 }; const saveObj = obj; obj.foo = 54; obj === saveObj Solution Use specialized objects which create new instance on modification Immutable.js library by Martin Kruliš (v1.1) 18. 4. 2019
Compatibility Issues Compatibility Issues ES6 is compatible with new browsers But not with the older ones The solution is to transpill ES6 to ES5 Same goes for JSX or TypeScript Missing functions can be polyfilled Babel.js A library for transpilling Can be used statically or dynamically Statically for production, dynamically for development https://babeljs.io/ by Martin Kruliš (v1.1) 18. 4. 2019
Modules Modules Compatibility and Bundling Modules cannot be easily transpilled They need to be bundled Compiled into one script file And possibly minimized Bundling also improves downloading Existing libraries Webpack Browserify by Martin Kruliš (v1.1) 18. 4. 2019
Code Linter Linter ESLint A tool that analyses source code Marks errors, suspicious constructs, stylistic errors, … Essential for interpreted languages Since there is no compilation ESLint Popular linter for JavaScript/ECMAScript Pluggable Plugin for VS Code exists https://eslint.org/ by Martin Kruliš (v1.1) 18. 4. 2019
Strict Mode Strict Mode Invoked by 'use strict' literal At the beginning of file or function Automatically invoked in modules and classes Mistakes are treated as error Accidental creation of global variables Using reserved words as identifiers … Disable some rare constructs in favor of improving variable handling efficiency Makes it easier to write more secure code by Martin Kruliš (v1.1) 18. 4. 2019
ECMAScript 7 (2016) ECMAScript 7 (2016) ECMAScript 8 (2017) Array includes() method Exponential operator ECMAScript 8 (2017) Async functions, await operator Shared buffers and atomic operations ECMAScript 9 (2018) Asynchronous iteration Rest/spread operators (…) for variables finally() for promises Regex improvements by Martin Kruliš (v1.1) 18. 4. 2019
Discussion by Martin Kruliš (v1.1) 18. 4. 2019