ES2015 (ES6) ------------ Here a list of the most used functionalities of ES2015 used in MapStore. Variable declaration ******************** Other than classical ``var``, you can declare variables using ``const`` and ``let`` .. code-block:: javascript // cannot be re-assigned new content, static check const a = “MY_CONST”; // block scoped var (var was function scope) let a = “myvar”; Functions ********* Default Value ::::::::::::: Now is possible to define a default value for function arguments. .. code-block:: javascript function fun(x = 42) { return x }; fun() // returns 42; fun(6*9) // returns 54 Rest Parameter :::::::::::::: The rest parameter syntax allows a function to accept an indefinite number of arguments as an array, providing a way to represent `variadic functions `_ in JavaScript. .. code-block:: javascript // rest parameter (array of last parameters) fun = function (a, ...b) { return b; } fun(1, 2, 3, 4); // return [2,3,4] Arrow Function :::::::::::::: **Arrow function** is a *concise syntax for writing (anonymous) function expressions*. They are anonymous and can be associated to a variable or passed as arguments to functions: .. code-block:: javascript const my = () => {}; // this is an empty function if function body is only one line long you can omit brackets ``{}`` and it will implicit return the expression value: .. code-block:: javascript () => 1; // this is a function that returns 1; if the function takes **only one** argument only, parenthesis for argument (``(argument)``) list are optionals. .. code-block:: javascript argument => value zero arguments, more than one argument using when using default values, you need parenthesis. .. code-block:: javascript () => 1; (arg1 = 1) => arg1; // returns arg1; (arg1, arg2) => arg1 + arg2; // returns arg1 + arg2; .. note:: For **one line arrow function** that returns an object, use `({})` (to avoid confusion with {} of function body) .. code-block:: javascript () => ({ object: "to return" }) .. note:: Unlike regular functions, arrow functions do not have their own this. The value of this inside an arrow function remains the same throughout the lifecycle of the function and is always bound to the value of this in the closest non-arrow parent function. .. code-block:: javascript let name = { fullName:'abc', printInRegular: function(){ console.log(`My Name is ${this.fullName}`); }, printInArrow:()=>console.log(`My Name is ${this.fullName}`) } name.printInRegular(); // My Name is abc name.printInArrow(); // My Name is undefined In this case the result of ``printInArrow`` will try to find the ``fullName`` property outside the name object and since it does not find anything it will print ``undefined`` For more details checkout `here `__ New Array Methods ::::::::::::::::: Map <<< The method **map** create a *new array* with the same length, with result of a function passed .. code-block:: javascript [1, 2, 3].map(a => a + 1) // [2,3,4] Filter <<<<<< The method **filter** creates a **new array** with only the elements that pass the test function passed .. code-block:: javascript [1, 2, 3].filter(a => a > 1) // [2,3] Reduce <<<<<< The method **reduce** allows to process arrays returning one result as an accumulation of the values. .. code-block:: javascript reduce( (accumulator, current) => nextAccumulatorValue, // reduce function (note implicit return) initialAccumulatorValue // initial value ) The *reduce function* is executed on every element of the array. The 2 arguments of the * ``accumulator``. It contains the ``initialAccumulatorValue`` on the first execution, the result of the previous execution on the next iterations. * ``current``. The current element of the array. Example: .. code-block:: javascript [1, 2, 3].reduce((accumulator, current) => accumulator + current, 0) // returns 6 Here below every executions, the arguments and the returned value on each iteration: 1. Arguments: ``(accumulator: 0, current: 1)`` -> returns ``0 + 1 = 1`` 2. Arguments: ``(accumulator: 1, current: 2)`` -> returns ``1 + 2 = 3``; 3. Arguments: ``(accumulator: 3, current: 3)`` -> returns ``3 + 3 = 6``; .. note:: If ``initialAccumulatorValue`` is ``undefined`` (or not passed), the execution will be different. Starting from the 2nd element of the array using 1st element of the array as accumulator). * (accumulator = 1, current = 2) returns 1 + 2 * (accumulator = 3, current = 3) returns 3 + 3 = 6 In this case the results are equal, but it is only a case. In general this is not true. For instance you may have: * ``[1,2,3].reduce((a,b) => a + b + 1, 0); // returns 9`` * ``[1,2,3].reduce((a,b) => a + b + 1); // returns 8`` Exercise: array methods ::::::::::::::::::::::: You can compose several function in cascade to transform filter and process your arrays: Example: .. code-block:: javascript [1, 2, 3] .map(a => a + 1) .filter(a => a > 1) .reduce((a, b) => a + b, 0) Solution: .. code-block:: javascript [1, 2, 3] .map(a => a + 1) // returns [2, 3, 4] .filter(a => a > 1) // returns --> [ 2, 3, 4] .reduce((a, b) => a + b, 0) // (acc: 0, curr: 2) = 2 // (acc: 2 + curr: 3) = 5 // (acc: 5 + curr: 4) = 9 Object initialization ********************* ES6 provides new notations for object initialization: **Shorthand property names** .. code-block:: javascript // Shorthand property names (ES2015) let a = 'foo', b = 42, c = {}; let o = {a, b, c} // shorthand for {a: a, b: b, c: c} **Computed property names** .. code-block:: javascript // Computed property names (ES2015) let prop = 'foo'; let o = { [prop]: 'hey', ['b' + 'ar']: 'there' } // o = {foo: 'hey', bar: 'there'} Spread operator *************** **Spread operator** (``...``) allows an **iterable** (arrays, objects) to expand in places where 0+ arguments are expected. Is widely used for array or objects. Example for array: .. code-block:: javascript var array = [3, 4] // Spread operator for arrays var newArray = [1, 2, ...array, 5] // result ->[1,2,3,4,5] (new Array) Here We can *spread* an array into a new array. Example for object: .. code-block:: javascript const obj = { b: "b", c: "c" }; // Spread operator for objects const newObj = { a: "a", ...obj, // spread obj into the new object d: "d" // define another attribute }; // newObj = { // a: "a", // b: "b", // c: "c", // d: "d" // } .. note :: In case you spread an object with the same properties names, the spread operation are applied in order an override the old with the new one *example*: .. code-block:: javascript const obj = { a: "b" }; // Spread operator for objects const newObj = { a: "a", ...obj // spread obj into the new object }; // newObj = { // a: "b" // } Destructuring assignment ************************ The destructuring assignment syntax is a JavaScript expression that makes it possible to unpack values from arrays, or properties from objects, into distinct variables. Example for arrays: .. code-block:: javascript const array = [1, 2, 3, 4]; const [c1, c2, ...rest] = array; // c1=1, // c2=2, // rest = [3, 4] Example for object: .. code-block:: javascript var obj = { a: "a", b: "b", c: "c" }; const { a, b: b1, ...rest } = obj; // equivalent of // a = "a"; // b1 = "b" // rest= {c:"c"} Classes ******* JavaScript Classes are templates for JavaScript Objects. .. code-block:: javascript class Car { // constructor constructor(brand) { this.carName = brand; } // method present() { return 'I have a ' + this.carName; } } //creating an instance const myCar = new Car("Ford"); // arguments for the constructor myCar.present(); // "I have a Ford"; typeof Car; // "function" A class, basically, is a special type of ``function``. We use the keyword ``class`` (sometimes called **syntactic sugar**) to better define the role of this function as a template for JavaScript Objects that should be used with the ``new`` construct. You can also use the ``extends`` keyword to implement inheritance: .. code-block:: javascript class Model extends Car { constructor(brand, mod) { super(brand); // call the "Car" constructor this.model = mod; } // add a new method show() { return this.present() + ', it is a ' + this.model; } } const mycar = new Model("Ford", "Mustang"); myCar.show(); // "I have a Ford, It's a Mustang" You can define ``static`` properties and methods for classes: .. code-block:: javascript class ClassWithStaticMethod { static staticProperty = 'someValue'; static staticMethod() { return 'static method has been called.'; } } console.log(ClassWithStaticMethod.staticProperty); // output: "someValue" console.log(ClassWithStaticMethod.staticMethod()); // output: "static method has been called." Classes are often used for define **React Components** (before functional components and hooks was introduced). Promise ******* An ES6 Promise is a pattern to represent and handle incomplete operations. The Promise object represents the eventual completion (or failure) of an asynchronous operation and its resulting value. .. code-block:: javascript var promise = new Promise(function (resolve, reject) { resolve(42); // here you can imagine ajax requests, setTimeout ... }); promise.then((function (result) { console.log(result); // 42 })); Chaining Promises ::::::::::::::::: Trying to chain asynchronous operations with using the classical callback method, leads to the classic callback pyramid of doom: .. code-block:: javascript doSomething(function(result) { doSomethingElse(result, function(newResult) { doThirdThing(newResult, function(finalResult) { console.log('Got the final result: ' + finalResult); }, failureCallback); }, failureCallback); }, failureCallback); With promises, if the function passed to then returns a Promise, it will be executed in chain. This allows write a more linear and readable code like the following: .. code-block:: javascript doSomething() .then(function(result) { return doSomethingElse(result); // returns a promise }) .then(function(newResult) { return doThirdThing(newResult); // returns a promise }) .then(function(finalResult) { console.log('Got the final result: ' + finalResult); }) .catch(failureCallback); Limitations of Promise :::::::::::::::::::::: There are some limitations of using promises: * **no cancellation**: the operation will be executed and will execute then (or catch) functions. There is no way to stop the execution (for instance an ajax request when the user press cancel). Some libraries (like axios) provide a cancellation extension, anyway this is not a feature of the Promise itserf. * **single value**: promises return only one single value and stop. This does not allow to manage streams of events (e.g. web sockets) * **complex data flows**: while it works perfectly for chaining simple operations, creating more complex data flows (conditional chaining and so on), may need a to still create some callback system. Axios ::::: `Axios `__ is a HTTP client library for the browser (and NodeJS) widely used, based on promises. It provides several simple functions to do AJAX requests: .. code-block:: javascript const ajaxCall = axios.get(“”); // axios.get returns a new Promise ajaxCall.then((function (result) { console.log(result); // ajax response object })); The library is widely used in MapStore and it will be used for all the examples