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
// 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.
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.
// 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:
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:
() => 1; // this is a function that returns 1;
if the function takes only one argument only,
parenthesis for argument ((argument)
) list are optionals.
argument => value
zero arguments, more than one argument using when using default values, you need parenthesis.
() => 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)
() => ({ 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.
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
[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
[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.
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 theinitialAccumulatorValue
on the first execution, the result of the previous execution on the next iterations.current
. The current element of the array.
Example:
[1, 2, 3].reduce((accumulator, current) => accumulator + current, 0) // returns 6
Here below every executions, the arguments and the returned value on each iteration:
Arguments:
(accumulator: 0, current: 1)
-> returns0 + 1 = 1
Arguments:
(accumulator: 1, current: 2)
-> returns1 + 2 = 3
;Arguments:
(accumulator: 3, current: 3)
-> returns3 + 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:
[1, 2, 3]
.map(a => a + 1)
.filter(a => a > 1)
.reduce((a, b) => a + b, 0)
Solution:
[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
// 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
// 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:
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:
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:
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:
const array = [1, 2, 3, 4];
const [c1, c2, ...rest] = array;
// c1=1,
// c2=2,
// rest = [3, 4]
Example for object:
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.
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:
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:
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.
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:
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:
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:
const ajaxCall = axios.get(“<URL>”); // 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