Новые стандарты
JavaScript

Жигалов Сергей

Кто?

Technical Committee 39

Как?

ES1 Jun 1997
ES2 Aug 1998
ES3 Dec 1999
ES4 ???
ES5 Dec 2009
ES6 (ECMAScript 2015) Jun 2015
ECMAScript 2016 (ES7) скоро

maturity stages

Stage 0: strawman

Рассмотрено на собрании TC39 и внесено в список предложений
page with proposals

Stage 1: proposal

Выбирается ответственный (champion) из числа TC39. Фича описывается в свободной форме, реализация сопровождается примерами, обсуждается семантика и алгоритмы

Stage 2: draft

Строгое описание синтиксиса и семантики, допустимы TODO. Две эксперементальные реализации, одна из которых может быть транспайлером.

Stage 3: candidate

Фича и описание готовы. Назначается ревьюверы. Должно быть не менее двух реализаций, совместимых с текущей версией спецификации. Сбор обратной связи.

Stage 4: finished

Все приемочные тесты проходят, практический опыт применения фичи. Описание подписано и готово для включения в спецификацию. Добавляется в ближайшую версию ECMAScript.

Arrow functions


() => { return true; }
        

() => true
        

[1, 2, 3].map(() => true);
        

// [true, true, true]
        

Arrow functions


item => item % 2
        

[1, 2, 3].map(item => item % 2);
        

// [1, 0, 1]
        

Arrow functions


(sum, item) => sum + item
        

[1, 2, 3].reduce(
    (sum, item) => sum + item
);
        

// 6
        

Arrow functions. this


function Person() {
    this.age = 0;

    setInterval(function() {
        this.age++;
    }, 1000);
}
        

var p = new Person();
console.log(p.age); // ?
        

Arrow functions. this


function Person() {
    this.age = 0;

    setInterval(() => {
        this.age++;
    }, 1000);
}
        

var p = new Person();
console.log(p.age); // ?
        

Arrow functions. arguments


[1, 2, 3].map(() => arguments[0]);
        

// ReferenceError:
//    arguments is not defined
        

Arrow functions


var simple = a => a > 15 ? 15 : a;
        
What

Spread operator


var arr = [3, 1, 5];
Math.min(...arr)
        

Spread operator


var sub = [3, 4, 5];
var all = [1, 2, ...sub, 6];

console.log(all);
// [1, 2, 3, 4, 5, 6]
        

Spread operator


var one, other;
[one, ...other] = [1, 2, 3, 4]

console.log(one);   // 1
console.log(other); // [2, 3, 4]
        

Default arguments


function timePerSlide(slides, duration = 90) {
    return duration / slides;
}
        


timePerSlide(30);     // 3
timePerSlide(20, 40); // 2
        

let


let year;
        

let firstName, lastName;
        

let city = 'Ekaterinburg';
        

let. Область видимости


if (true) {
    var secret = 'Top secret!';
}

console.log(secret);
        

// Top secret!
        

let. Область видимости


if (true) {
    let secret = 'Top secret!';
}

console.log(secret);
        

// ReferenceError:
//     secret is not defined
        

let


let remember;
        

let remember;
        

// SyntaxError:
//   Identifier 'remember' has
//   already been declared
        

let. temporal dead zone


function doWeather() {
    console.log(temperature);
    let temperature = 10;
}
        

// ReferenceError:
//   temperature is not defined
        

const


const zero = 0;
        

const winterDuration = 3,
      uralWeather = 'bad';
        

const


const students = [];
        

students.push('Аня');
students.push('Федя');
students.push('Катя');
        
surprise

bloсk-level function declaration


'use strict';
function answer() {
    return 'Yes';
}

if (true) {
    function answer() {
        return 'No';
    }
}
        

bloсk-level function declaration


answer();
        

// Yes
        

Number


Number.EPSILON
        

Number.isInteger(Infinity) // false
        

Number.isNaN("NaN") // false
        

Math


Math.acosh(3)
        

Math.hypot(3, 4) // 5
        

Math.imul(Math.pow(2, 32) + 2, 2) // 4
        

String


'паром'.includes('ром') // true
        

'oh'.repeat(3)          // ohohoh
        

Array


Array.of(1, 2, 3); // [1, 2, 3]
        

[0, 0, 0].fill(7, 1); // [0, 7, 7]
        

[1, 2, 3].find(x => x === 3); // 3
        

[1, 2, 3].findIndex(x => x === 2); // 1
        

[1, 2, 3, 4, 5].copyWithin(3, 0);
// [1, 2, 3, 1, 2]
        

Array


['a', 'b', 'c'].entries();
// iterator [0, 'a'], [1,'b'], [2,'c']
        

['a', 'b', 'c'].keys(); // iterator 0, 1, 2
        

['a', 'b', 'c'].values(); // iterator 'a', 'b', 'c'
        

[1, 2, 3].includes(2);   // true
        

Object


var car = {model: 'BMW M3'};
Object.assign(car, { color: 'blue' });
// {model: "BMW M3", color: "blue"}
        

car
// {model: "BMW M3", color: "blue"}
        

Object.keys(car);
// ["model", "color"]
        

Destructuring


var one, two;
[one, two] = [1, 2];

console.log(one); // 1
console.log(two); // 2
        

Destructuring


var one, two;
[one=1, two=2] = [11];

console.log(one); // 11
console.log(two); // 2
        

Destructuring


var one = 1;
var two = 2;
[one, two] = [two, one];

console.log(one); // 2
console.log(two); // 1
        

Destructuring


var one, three;
[one, , three] = [1, 2, 3];

console.log(one);   // 1
console.log(three); // 3
        

Destructuring


var one, two;
var {one, two} = {one: 1, two: 2};

console.log(one); // 1
console.log(two); // 2
        

Destructuring


var one;
var {number: one} = {number: 1};

console.log(one); // 1
        

Destructuring


var one, two;
var {one=1, two=2} = {one: 12};

console.log(one); // 12
console.log(two); // 2
        

Classes

Classes


class Lecture {
    constructor(course, title) {
        this.course = course;
        this.title = title;
    }
}
        

Classes. Methods


class Lecture {
    constructor(course, title) {
        this.course = course;
        this.title = title;
    }

    getId() {
        return this.course + '_' + this.title;
    }
}
        

Classes. Methods


var lecture = new Lecture('WebDev', 'ES.next');

lecture.getId(); // 'WebDev_ES.next'
        

Classes. Fields


class Lecture {
    constructor(title) {
        this.title = title;
    }

    set duration(value) {
        this._duration = value;
    }

    get duration() {
        return this._duration;
    }
}
        

Classes. Fields


var lecture = new Lecture('ES.next');

lecture.title; // ES.next

lecture.duration = 120;
lecture.duration; // 120
        

Classes. Static


class Lecture {
    static from() {
        return 'Yandex';
    }
}
        

Lecture.from(); // Yandex
        

Classes. extends


class WebApiLecture extends Lecture {
    constructor(course, title) {
        super(course, 'API_' + title);
    }
        
    get isMultiTeacher () {
        return true;
    }
    getId() {
        return super.getId() + '_WithAnimations';
    }
}

Classes. extends


var lecture = new WebApiLecture('WebDev', 'Part1');

lecture.isMultiTeacher; // true
lecture.getId(); // WebDev_API_Part1_WithAnimations
        

Enhanced Object Literals


var name = 'Сергей';
var lecturer = { name: name };
        


var lecturer = { name };
        

Enhanced Object Literals


var lecturer = {
    name: 'Сергей',
    toString() {
        return this.name + ': ' +
            super.toString();
    }
};
        

'' + lecturer;
// Сергей: [object Object]
        

Enhanced Object Literals


var foolObj = {
    [Math.random()]: 'Unpredictable!'
};
        


JSON.stringify(foolObj);
// {"0.0054615481669":"Unpredictable!"}
        

Map


var car = new Map();
car.set('name', 'BMW i8');
        


var engine = {capacity: '1499'};
car.set(engine, {consumption: 2.1});
        

Map


function drive () {};
car.set(drive, () => new Error('...'));
        


car.get('name'); // BMW i8
car.size;        // 3
        

Map


for (var key of car.keys()) {
    console.log(key);
}
        

for (var value of car.values()) {
    console.log(value);
}
        

for (var [key, value] of car.entries()) {
    console.log(key + ' => ' + value);
}
        

Set


var mentors = new Set();
        

mentors.add('Олег Олегыч');
mentors.add('Олег Львович');
mentors.add('Олег Львович');
        

mentors.size; // 2
        

Set


for (var mentor of mentors) {
    console.log(mentor);
}
        

// Олег Олегыч
// Олег Львович
        

Template literals


var str = `Multi-line
template string`
        

console.log(str);
// Multi-line
// template string
        

Template literals


var name = 'Сергей'
var greet = `Привет, ${name}!`
        

console.log(greet);
// Привет, Сергей!
        

Template literals


var math = `√25 = ${Math.sqrt(25)}`
        

console.log(math);
// √25 = 5
        

Template literals


var name = 'Сергей'
function tag(strings, value) {
    strings[0]; //  'Привет, ';
    strings[1]; //  '!';
    value;      //  'Сергей';

    return 'Нормально делай, нормально будет';
}
var greet = tag`Привет, ${name}!`
        

Template literals


console.log(greet);
// Нормально делай, нормально будет
        

Generators


function *incremental() {
    var i = 0;

    while(true) {
        yield i++;
    }
}
        

Generators


var it = incremental();
        

it.next(); // {value: 0, done: false}
        

it.next(); // {value: 1, done: false}
        

it.next(); // {value: 2, done: false}
        

Generators


function *steps() {
    yield 'Отрицание';
    yield 'Гнев';
    yield 'Торги';
    yield 'Депрессия';
    yield 'Принятие';
}
        

Generators


for (var step of steps()) {
    console.log(step);
}
        

// Отрицание
// Гнев
// Торги
// Депрессия
// Принятие
        

Typed arrays

Int8Array 1
Uint8Array 1
Uint8ClampedArray 1
Int16Array 2
Uint16Array 2
Int32Array 4
Uint32Array 4
Float32Array 4
Float64Array 8

Typed arrays


var arr = new Int8Array([1, 100, 200]);
        

console.log(arr); // [1, 100, -56]
        

new.target


function Factory() {
    console.log(new.target);
}
        

Factory();     // undefined
        

new Factory(); // Factory {}
        

Async functions


function timeout(time) {
    return new Promise(function (resolve) {
        setTimeout(resolve, time);
    });
}
        

Async functions


async function legendarily() {
    console.log('Леген...');
    await timeout(1000);

    console.log('подожди-подожди');
    await timeout(1000);

    console.log('...дарно!');
}
        

Async functions


legendarily()
    .then(() => console.log('done'));
        

Async functions


(async () => {
    await legendarily();
    console.log('done');
})()
        

Modules


// lib/math.js
export function sum(x, y) {
    return x + y;
}
export var pi = 3.141593;
        

Modules


import * as math from 'lib/math';

console.log('2π = ' + math.sum(math.pi, math.pi));
        

Modules


import {sum, pi} from 'lib/math';

console.log('2π = ' + sum(pi, pi));
        

Modules


// lib/mathplusplus.js
export * from 'lib/math';
export var e = 2.71828182846;
export default function(x) {
    return Math.exp(x);
}
        

Modules


import exp, {pi, e} from 'lib/mathplusplus';

console.log('e^π = ' + exp(pi));
        

Поддержка

Babel


npm install --save-dev babel-cli
        

babel src --out-dir build --source-maps
        

.babelrc


{
    "presets": ["es2015"],
    "plugins": [
        "syntax-async-functions",
        "transform-regenerator",
        ...
    ]
}
        

demo