ES2015, ES2016, ES2017
Samuel Silva
Arrow Function, Classes, Destructuring Assignment, Spread, Rest
The ECMAScript specification is a standardized specification of a scripting language developed by Brendan Eich of Netscape.
Initially it was named Mocha, later LiveScript, and finally JavaScript
- June 2015
- Initially known as ECMAScript 6 (ES6) and later renamed to ECMAScript 2015 (ES2015)
- Iterators and for/of loops, Python-style generators and generator expressions, arrow functions, binary data, typed arrays, collections (maps, sets and weak maps), promises, number and math enhancements, reflection, and proxies (metaprogramming for virtual objects and wrappers)
- June 2016
- the exponentiation operator (**) and Array.prototype.includes
- June 2017
- includes features for concurrency and atomics, syntactic integration with promises (async/await)
An arrow function expression has a shorter syntax than a function expression and does not have its own this, arguments, super, or new.target. These function expressions are best suited for non-method functions, and they cannot be used as constructors.
const sum = (arg1, arg2) => {
return arg1 + arg2
}
const sum = (arg1, arg2) => arg1 + arg2
const test = arg1 => arg1
Arrow functions don't 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)
// Example using a function expression
function createObject() {
console.log('Inside `createObject`:', this.foo);
return {
foo: 42,
bar: function() {
console.log('Inside `bar`:', this.foo);
},
};
}
createObject.call({foo: 21}).bar(); // override `this` inside createObject
// Inside `createObject`: ?
// Inside `bar`: ?
// Example using a arrow function
function createObject() {
console.log('Inside `createObject`:', this.foo);
return {
foo: 42,
bar: () => console.log('Inside `bar`:', this.foo),
};
}
createObject.call({foo: 21}).bar(); // override `this` inside createObject
// Inside `createObject`: ?
// Inside `bar`: ?
const argFunction = function () {
console.log('arguments', arguments);
}
const argArrow = () => {
console.log('arguments', arguments);
}
console.clear();
argFunction(1, 2, 3, 4) // ?
argArrow(1, 2, 3, 4) // ?
Arguments
// Function expresssion are constructable
const Person = function (name, age) {
this.name = name;
this.age = age
}
const person = new Person('Samuel', 28)
// Arrow Functions are not constructable.
const PersonArrow = (name, age) => {
this.name = name;
this.age = age;
}
const personArrow = new PersonArrow('Samuel', 28)
console.clear();
console.log(person) // ?
console.log(personArrow) // ?
Constructor
JavaScript classes, introduced in ECMAScript 2015, are primarily syntactical sugar over JavaScript's existing prototype-based inheritance.
The class syntax does not introduce a new object-oriented inheritance model to JavaScript.
class Person {
constructor(name, age) {}
}// old way
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.setName = function(name) {
this.name = name;
}
// new way with classes
class PersonClass {
constructor(firstName, lastName, age) {
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
}
setFirstName(firstName) {
this.firstName = firstName;
}
get fullName() {
return `${this.firstName} ${this.lastName}`
}
}
const samuel = new Person('Samuel', 28);
const samuelClass = new PersonClass('Samuel', 'Castro', 28)
samuel.setName('Samuel Castro');
samuelClass.setFirstName('New First Name')
console.log(samuel); // Person {name: "Samuel Castro", age: 28}
console.log(samuelClass); // PersonClass {firstName: "Samuel Castro", lastName: "Castro", age: 28}
console.log(samuelClass.fullName) // New First Name Castrostatic
class MyClass {
static test() {
console.log('testing')
}
}
MyClass.test() // testing
extends
class Person {
constructor(name) {
this.name = name
}
}
class Dev extends Person {
constructor(name, skills) {
super(name);
this.skilss = skills
}
}
const samuel = new Dev('Samuel', ['js', 'react', 'etc'])
console.clear();
console.log(samuel) // Dev {name: "Samuel", skilss: Array(3)}
console.log(samuel instanceof Dev) // true
console.log(samuel instanceof Person) // true
The destructuring assignment syntax is a JavaScript expression that makes it possible to unpack values from arrays, or properties from objects, into distinct variables.
let a, b, rest;
[a, b] = [10, 20];
console.log(a); // 10
console.log(b); // 20
[a, b, ...rest] = [10, 20, 30, 40, 50];
console.log(rest); // [30,40,50]
Arrays
const {c, d} = {c: 30, d: 40};
console.log(c); // 30
console.log(d); // 40Objects
Functions
const testArray = ([,, name]) => console.log(name);
const testObject = ({a: {b: {c: d}}}) => console.log(d);
const object = {
a: {
b: {
d: 'testD',
c: 'testC',
}
}
}
testArray(["Samuel", "Daniel", "Test"]); // ?
testObject(object); // ?
Spread syntax allows an iterable such as an array expression or string to be expanded in places where zero or more arguments (for function calls) or elements (for array literals) are expected, or an object expression to be expanded in places where zero or more key-value pairs (for object literals) are expected.
Rest parameter syntax allows us to represent an indefinite number of arguments as an array.
const doSomething = (a, ...b) => { // rest operator
console.log(a);
console.log(b);
}
doSomething('add', 1, 2, 3);
// a = 'add' (string)
// b = [1, 2, 3] (array)
const add = (a, ...b, c) => {}
// SyntaxError: Rest parameter must be last formal parameterRest
Spread
const add2 = (...numbersToAdd) => { // This is a Rest parameter
return numbersToAdd.reduce((sum, next) => sum + next);
}
const numbers = [1, 2, 3];
const result1 = add2(...numbers); // this is a Spread operator
// The above is functionally the same as:
const result2 = add2(1, 2, 3);
console.log(result1); // 6
console.log(result2); // 6const fruits = ['apple', 'orange'];
const allFruits = ['strawberry', ...fruits, 'watermelon'];
// ["apple", "strawberry", "apple", "orange", "watermelon"]const arr = [1, 2, 3];
const arr2 = [...arr]; // like arr.slice()
arr2.push(4);
// arr2 becomes [1, 2, 3, 4]
// arr remains unaffectedconst arr1 = [0, 1, 2];
const arr2 = [3, 4, 5];
// concat
arr1 = arr1.concat(arr2);
// spread
arr1 = [...arr1, ...arr2]Array Literal
Copy Arrays
Concatenate Arrays
const obj1 = { foo: 'bar', x: 42 };
const obj2 = { foo: 'baz', y: 13 };
const clonedObj = { ...obj1 };
// Object { foo: "bar", x: 42 }
const mergedObj = { ...obj1, ...obj2 };
// Object { foo: "baz", x: 42, y: 13 }
Objects
const a = {test: 'ok'};
const b = a
const c = {...a}
console.log(a === b); // ?
console.log(a === c); // ?Spread will create a new object
const a = {
name: 'samuel'
};
const b = a;
const c = b;
const d = c;
const e = d;
const f = {...e};
e.name = 'daniel';
console.log(a); // ?
console.log(e); // ?
console.log(f); // ?What's the value of a, e and f and why?
function todoApp(state = initialState, action) {
switch (action.type) {
case SET_VISIBILITY_FILTER:
return { ...state, visibilityFilter: action.filter }
default:
return state
}
}Spread Operator and React Reducers
Immutability vs Mutability
But Why?