ES2015+

Василий Кузнецов

ECMAScript

  • официальное название JavaScript
  • принадлежит ассоциации Ecma
  • Technical Committee 39 развивает ECMAScript
  • github.com/tc39/tc39-notes
  • ECMAScript 2015 (ES6) принят 17 июня 2015
  • ECMAScript 2016 принят 14 июня 2016
  • ECMAScript 2017 разрабатывается

let

if (true) {
    var a = 10;
}

console.log(a);//10

let

if (true) {
    let a = 10;
}

console.log(a);//ReferenceError: a is not defined

let

console.log(a);

let a = 10;//ReferenceError: a is not defined

let

let a;
let a;//SyntaxError: Identifier 'a' has already been declared

const

const pi = 3.14;pi = 3;//TypeError: Assignment to constant variable.

const

const animals = ['cat'];animals[0] = 'dog';
animals.push('bird');
//['dog', 'bird']

const

const animal = { name: 'Барсик' };animal.type = 'cat';
animal.color = 'black';
//{ name: 'Барсик', type: 'cat', color: 'black' }

Arrow functions

function (name, surname) {
    const greeting =
        'hello, ' +
        name +
        ' ' +
        surname;

    return greeting;
}
(name, surname) => {
    const greeting =
        'hello,' +
        name +
        ' ' +
        surname;

    return greeting;
}

Arrow functions

function (name) {
    const greeting =
        'hello, ' +
        name;

    return greeting;
}
name => {
    const greeting =
        'hello,' +
        name;

    return greeting;
}

Arrow functions

function (name) {
    return 'hello, ' + name;
}
name => 'hello, ' + name;

Arrow functions

this.showPictures = function () {
    this.pictutes.forEach(function (picture) {
        picture.isShown = true;
        this.showPicture(picture);
    }, this);
}

Arrow functions

this.showPictures = () => {
    this.pictutes.forEach(picture => {
        picture.isShown = true;
        this.showPicture(picture);
    });
}

Arrow functions

function traditionalFunction() {
    const arrowFunction = () => console.log(arguments);

    arrowFunction('arrow function');
}

traditionalFunction('traditional function');//{ '0': 'traditional function' }

Arrow functions

const Func = () => this.a = 2;
new Func()//TypeError: Func is not a constructor

Default arguments

function pow(base, exponent) {
    exponent = exponent === undefined ? 2 : exponent;

    return Math.pow(base, exponent);
}

Default arguments

function pow(base, exponent = 2) {
    return Math.pow(base, exponent);
}
pow(2);     //4
pow(2, 3);  //8

Spread operator

Math.max.apply(Math, [-1, 5, 11, 3])
//11
Math.max(...[-1, 5, 11, 3])
//11

Spread operator

const pets = ['cat', 'dog'];
const animals = ['bird', ...pets];//['bird', 'cat', 'dog']

Destructuring

const array = [1, 2];const first = array[0];
const second = array[1];
const array = [1, 2];
const [first, second] = array;

console.log(first);  // 1
console.log(second); // 2

Destructuring

const [first, , third] = [1, 2, 3];

console.log(first); // 1
console.log(third); // 3

Destructuring

const [first, second, ...other] = [1, 2, 3, 4, 5];

console.log(first);  // 1
console.log(second); // 2
console.log(other);  // [ 3, 4, 5 ]

Rest parameters

function func(first, second, ...other) {
    console.log(first);  // 1
    console.log(second); // 2
    console.log(other);  // [ 3, 4, 5 ]
}

func(1, 2, 3, 4, 5);

Destructuring

const [first, second = 2 ] = [1];

console.log(first);  // 1
console.log(second); // 2

Destructuring

const person = {
    name: 'Vasya',
    age: 22,
    gender: 'male'
};
const { name, age } = person;

console.log(name); // Vasya
console.log(age);  // 22

Destructuring

const person = {
    name: 'Vasya',
    age: 22,
    gender: 'male'
};
const { name: login } = person;

console.log(login); // Vasya

Destructuring

const person = {
    age: 22,
    gender: 'male'
};
const { name = 'noname' } = person;

console.log(name); // noname

Destructuring

const person = {
    name: 'Vasya',
    hair: { color: 'black', length: 'short' }
};
const {
    name,
    hair: { color: hairColor, length },
    eyes: { color: eyeColor = 'green' } = {}
} = person;

Destructuring

function happyBirthday({ name, age }) {
    return 'Happy birthday, ' + name + '!\n' +
        'You are ' + age + ' years old now!';
}
happyBirthday({ name: 'Vasya', age: 22 })
//Happy birthday, Vasya!
//You are 22 years old now!

Template literals

function happyBirthday({ name, age }) {
    return `Happy birthday, ${name}!
You are ${age} years old now!`;
}
happyBirthday({ name: 'Vasya', age: 22 })
//Happy birthday, Vasya!
//You are 22 years old now!

Template literals

function tag(strings, value1, value2) {
    console.log(strings);
    // [ 'Happy birthday, ','! You are ', ' years old now!' ]
    console.log(value1);  // Vasya
    console.log(value2);  // 22
    return `${value1} - ${value2}`;
}
const { name, age } = { name: 'Vasya', age: 22 };
tag`Happy birthday, ${name}! You are ${age} years old now!`;//Vasya - 22

Template literals

import gql from 'graphql-tag';
const query = gql`
    query Student($id: ID!) {
        student(id: $id) {
            name
            group {
                name
            }
        }
    }
`;

Template literals

function gql(/* arguments */) {
  var args = Array.prototype.slice.call(arguments);
  var literals = args[0];
  var result = literals[0];
  for (var i = 1; i < args.length; i++) {
    if (args[i] && args[i].kind && args[i].kind === 'Document') {
      result += args[i].loc.source.body;
    } else {
      result += args[i];
    }
    result += literals[i];
  }
  return parseDocument(result);
}

for-of

['cat', 'dog', 'bird'].forEach(animal => {
    console.log(animal);
});

for-of

const animals = ['cat', 'dog', 'bird'];

for (const animal of animals) {
    if (animal === 'human') {
        break;
    }
    console.log(animal);
}

for-of

const animals = ['cat', 'dog', 'bird'];

for (const [index, animal] of animals.entries()) {
    console.log(index, animal);
}//0 cat
//1 dog
//2 bird

Array

Array.from({ length: 2, 0: 'a', 1: 'b' }) //['a', 'b']Array.from([1, 2, 3], x => x * x) //[1, 4, 9]Array.of(1, 2, 3) //[1, 2, 3]

Array

Array.from(['a', 'b'].keys()) //[ 0, 1 ]Array.from(['a', 'b'].values()) //[ 'a', 'b' ]Array.from(['a', 'b'].entries())
//[
//    [ 0, 'a' ],
//    [ 1, 'b' ]
//]

Array

[6, -5, 8].find(x => x < 0) //-5[6, -5, 8].findIndex(x => x < 0) //1[1, 2, 3].fill(7) //[ 7, 7, 7 ][1, 2, 3].includes(2) //true

Array

arr.includes(x)
arr.indexOf(x) >= 0[NaN].includes(NaN) //true
[NaN].indexOf(NaN) //-1

String

'hello'.startsWith('hell') //true'hello'.endsWith('llo') //true'hello'.includes('ell') //true'hello '.repeat(3) //hello hello hello

Object

const name = 'Vasya';
const objectWithName = { name };const objectWithAge = { ['ag' + 'e']: 22 };const person = {};
Object.assign(person, objectWithName, objectWithAge);//person
//{
//    name: 'Vasya',
//    age: 22
//}

Object

const object = {
    name: 'Vasya',
    hair: { color: 'black' }
};
const clone = Object.assign({}, object);object.hair.color = 'blonde';//clone
//{
//    name: 'Vasya',
//    hair: { color: 'blonde' }
//}

Object

const object1 = { name: 'Vasya' };
const object2 = { name: 'Petya' };
Object.assign({}, object1, object2);//{ name: 'Petya' }

Object

const name = 'Vasya';
const person = {
    name: 'Vasya',
    getGreeting() {
        return `Hello, ${this.name}`;
    }
 };person.getGreeting() // Hello, Vasya

Map

const map = new Map();map.set('key', 5)map.get('key') // 5map.has('key') // truemap.delete('key')
map.has('key') // false

Map

const map = new Map();
const KEY = { id: 1 };map.set(KEY, 5)map.get(KEY) // 5map.get({ id: 1}) // undefinedmap.set(NaN, 10)map.get(NaN) // 10

Map

const map = new Map();
const KEY = { id: 1 };
map
    .set(KEY, { value: 10 })
    .set('key', 5)
    .set(Math.pow, a => a * a);map.size // 3map.clear();
map.size // 0

Map

const map = new Map([
    [{ id: 1 }, { value: 10 }],
    ['key', 5]
]);
map.keys() //MapIterator { { id: 1 }, 'key' }
map.values() //MapIterator { { value: 10 }, 5 }
map.entries()
//MapIterator { [ { id: 1 }, { value: 10 } ], [ 'key', 5 ] }

Set

const set = new Set();set.add('key')set.has('key') // trueset.delete('key')
set.has('key') // false

Set

const set = new Set();
const KEY = { id: 1 };set.add(KEY)set.has(KEY) // trueset.has({ id: 1}) // falseset.add(NaN)set.has(NaN) // true

Set

const set = new Set();
const KEY = { id: 1 };
set
    .add(KEY)
    .add('key')
    .add('key')
    .add(Math.pow);set.size // 3set.clear();
set.size // 0

Set

const set = new Set([
    { id: 1 },
    'key'
]);
for (const elem of set) {
    console.log(elem);
}//{ id: 1 }
//key

Set

const array = ['a', 1, 'a', 2, '1'];
const unique = [...new Set(array)];
//['a', 1, 2, '1']

Class

class Point {
    constructor(x, y) {
        this.x = x;
        this.y = y;
    }
    toString() {
        return `(${this.x}, ${this.y})`;
    }
}

Class

const p = new Point(1, 2);
p.toString() // (1, 2)
p instanceof Point // true
typeof Point // function

Class

const p = Point(1, 2);//TypeError: Class constructor Point cannot be invoked
//without 'new'

Class

class Point {
    constructor(x, y) {
        this.x = x;
        this.y = y;
    }
    static getZero() { return new Point(0, 0); }
    toString() { return `(${this.x}, ${this.y})`; }
}
Point.getZero() //Point { x: 0, y: 0 }

Class

class Point {
    constructor(x) { this._x = x; }
    get x() { return this._x; }
    set x(value) { this._x = value; }
}
const p = new Point(1);
p.x // 1
p.x = 2;
p.x // 2

Class

class ColorPoint extends Point {
    constructor(x, y, color) {
        super(x, y);
        this.color = color;
    }
    toString() {
        return `${super.toString()} #${this.color}`;
    }
}

Class

const p = new ColorPoint(1, 2, 'fff');
p.toString() //(1, 2) #fff

Async functions

async function foo() {}
const foo = async function () {};
let obj = { async foo() {} }
const foo = async () => {};

Async functions

async function asyncFunc() {
    return 123;
}
/*async function asyncFunc() {
    return Promise.resolve(123);
}*/
asyncFunc().then(x => console.log(x));
// 123

Async functions

async function asyncFunc() {
    throw new Error('error');
}
/*async function asyncFunc() {
    return Promise.reject(new Error('error'));
}*/
asyncFunc().catch(error => console.log(error));
// Error: error

Async functions

async function asyncFunc() {
    const result = await otherAsyncFunc();
    console.log(result);
}

Async functions

async function asyncFunc() {
    try {
        await otherAsyncFunc();
    } catch (err) {
        console.error(err);
    }
}

Async functions

(async () => {
    console.log(await asyncFunction());
})();

Async functions

async function func() {
    const result1 = await asyncFunc1();
    const result2 = await asyncFunc2();
}
//выолняется последовательно

Async functions

async function func() {
    const [result1, result2] = await Promise.all([
        asyncFunc1(),
        asyncFunc2()
    ]);
}
//выолняется параллельно

Async functions

async function func() {
    return await asyncFunction();
}
=
async function func() {
    return asyncFunction();
}

Modules

//math.js
function add(a, b) { return a + b; }
function mult(a, b) { return a * b; }
var pi = 3.14;
module.exports = {
    add: add,
    mult: mult,
    pi: pi
};

Modules

//math.js
export function add(a, b) { return a + b; }
export function mult(a, b) { return a * b; }
export const pi = 3.14;

Modules

import { pi, add } from './math';
add(2, pi) // 5.14

Modules

import * as math from './math';
math.add(2, math.pi) // 5.14
math.mult(2, 2) // 4

Modules

//math.js
export default function add(a, b) { return a + b; }
export function mult(a, b) { return a * b; }
export const pi = 3.14;

Modules

import add, { pi } from './math';
add(2, pi) // 5.14

Modules

//supermath.js
export * from './math';
export function sub(a, b) { return a - b; }
Поддержка ES6
Поддержка ES2016+

Babel

npm install --save-dev babel-cli babel-preset-es2015
./node_modules/.bin/babel index.js --presets es2015
echo '{ "presets": ["es2015"] }' > .babelrc
./node_modules/.bin/babel index.js

Babel

Песочница

Ссылки

JavaScript books by Dr. Axel Rauschmayer
https://github.com/lukehoban/es6features
es6 in depth