ESNext: Сколько можно ждать?

(или как начать пользоваться уже сегодня)

bit.ly/1ru9A8z

ECMAScript

сейчас

Нововведения

(некоторые)

Let и Const

Let

// Ошибка: `x` не определена
console.log(x);

let x;

// undefined
console.log(x);

Const

// Ошибка: `x` не определена
console.log(x);

const x = 0;

Числа

Числа

Новые литералы

// Двоичные
0b1001 === 9            // true
0B10010 === 18          // true

// Восьмеричные
0o755 === 493           // true
0O451 === 297           // true

// Шестнадцатеричные
0xFF === 255            // true
0X7C9D === 31901        // true

Числа

Улучшения конструктора

// Исправленные isNaN(), isFinite()
Number.isNaN(value)
Number.isFinite(value)

Объекты

Объекты

Сокращенная нотация

ES5

var value = 42;

var obj = {
  value: value,

  getValue: function() {
    return this.value;
  }
};

obj['foo' + 'bar'] = value;

ES6

var value = 42;

var obj = {
  value,

  getValue() {
    return this.value;
  },

  ['foo' + 'bar']: value
};

Объекты

Улучшения конструктора

// Исправленное ===
Object.is(NaN, NaN);                  // true
Object.is(-0, 0);                     // false
// Присваивает собственные перечисляемые свойства
Object.assign({
  foo: 'foo'
}, { foo: 'bar'}, { foo: 'baz' });    // { foo: 'baz' }

Объекты

Улучшения конструктора

// Использует геттеры
let bar = {
  get foo() {
    return 'bar';
  }
};

Object.assign({}, foo);             // { foo: 'bar' }

Объекты

Улучшения конструктора

// И сеттеры
let baz = {
  _foo: 'foo',

  set foo(val) {
    this._foo = val + 'baz';
  }
};

Object.assign(baz, { foo: 'bar' }); // { _foo: 'barbaz', ... }

Функции

Функции

Arrow функции

=>

Аналогичны анонимным функциям с bind(this)

let empty = () => {};
let identify = x => x;

// Объект необходимо заворачивать в ()
let objectify = value => ({ key: value });
let squares = [1, 2, 3].map(x => x * x);

let odds = [1, 2, 3].filter(x => {
  let isOdd = x % 2 === 0;
  return isOdd;
});

Функции

Arrow функции

  • Упрощенный синтаксис
  • Полезны в местах где меняется контекст: таймеры, обработчики событий
  • this привязан лексически, невозможно использовать в качестве конструктора
  • Функции анонимны, нет информации для отладки

Функции

Параметры по умолчанию

||

function log(message) {
  message = message || 'Default message';
  console.log(message);
}

Функции

Параметры по умолчанию

typeof

function substr(str, start, count) {
  start = (typeof start !== 'undefined') ? start : 0;
  count = (typeof count !== 'undefined') ?
          count :
          str.length - start;

  return str.slice(start, end);
}

Функции

Параметры по умолчанию

arguments

function substr(str, start, count) {
  var len = arguments.length;

  start = (len > 1) ? start : 0;
  count = (len > 2) ? count : str.length - start;

  return str.slice(start, end);
}

Параметры по умолчанию

ES6

function log(message = 'Default message') {
  console.log(message);
}

function substr(str, start = 0, count = str.length - start) {
  return str.substr(start, count);
}

Функции

Rest параметры

ES5

function f(head) {
  var tail = Array.prototype.slice.call(arguments, f.length);
  return tail;
}

ES6

function f(head, ...tail) {
  return tail;
}

f(1, 2, 3);     // [2, 3]
f(1);           // []

Функции

Rest параметры

function sum(...numbers) {
  return numbers.reduce(function(memo, n) {
    return memo + n;
  });
}

console.log(sum(1, 2, 3, 4, 5)); // 15

Функции

Оптимизация хвостовой рекурсии

Обычная рекурсия

function factorial(n) {
  if (n === 0) return 1;

  // Результат рекурсивного вызова модифицируется
  return n * factorial(n - 1);
}

console.log(factorial(100000));

Функции

Оптимизация хвостовой рекурсии

Стек вызовов

call factorial(3)        // Фрэйм 1
  call factorial(2)      // Фрэйм 2
    call factorial(1)    // Фрэйм 3
      call factorial(0)  // Фрэйм 4 и т.д.
      return 6
    return 6
  return 6
return 6

Функции

Оптимизация хвостовой рекурсии

Функции

Оптимизация хвостовой рекурсии

Хвостовая рекурсия

function tailFactorial(n, acc = 1) {
  if (n === 0) return acc;

  // Возвращается чистый вызов рекурсии
  return tailFactorial(n - 1, n * acc);
}

// C оптимизацией хвостовой рекурсии ошибки не будет
console.log(tailFactorial(100000));

Функции

Оптимизация хвостовой рекурсии

Стек вызовов

call tailFactorial(3, 1)  // Фрэйм 1

replace args with (2, 3)
jump tailFactorial        // Использовать фрэйм 1

replace args with (1, 6)
jump tailFactorial        // Использовать фрэйм 1

replace args with (0, 6)
jump tailFactorial        // Использовать фрэйм 1

Строки

Строки

Улучшения прототипа

String.prototype.repeat(value)

String.prototype.startsWith(value)
String.prototype.endsWith(value)

String.prototype.contains(value)

Строки

Template literals

`

Простой пример

let evt = {
  name: 'WSD',
  desc: 'awesome'
};

console.log(`${evt.name} is ${evt.desc}`); // WSD is awesome

Строки

Tags

Сигнатура тега

function tag(strings, ...values) {
  // Преобразует строки
  // Преобразует значения

  // Возвращает строку
}

// Использование
tag `Template literal`;
tag(strings, ...values);

Строки

Tagged template literals

Простой пример

function echo() {
  return 'You shall not pass!';
}

let naive = echo `I'm the mighty string!`;

console.log(naive); // You shall not pass!

Строки

Tagged template literals

Полезный пример

function shoutify(strings, ...values) {
  values = values.map(function(val) {
    return val.toUpperCase();
  });

  return String.raw(strings, ...values);
}

let loudly = shoutify `You, ${'shall'} not ${'pass'}!`

console.log(loudly); // You, SHALL not PASS!

Массивы

Массивы

Улучшения конструктора

Array.of

// Произвольное число аргументов -> Массив
Array.of(element0, ..., elementN)

// Реализация с помощью rest параметров
Array.of = function(...args) {
  return args;
};

Массивы

Улучшения конструктора

Array.from

// arguments, NodeList -> Массив
Array.from(arrayLike, mapFn, thisArg)

function f() {
  return Array.from(arguments);
}
f(1, 2, 3); // [1, 2, 3]

Array.from('1234'); // ['1', '2', '3', '4']

Array.from(document.querySelectorAll('div')); // [<div>, ...]

Массивы

Улучшения прототипа

fill

Array.prototype.fill(value, start = 0, end = this.length)

let arr = [0, 0, 0].fill(1, 0, 3); // [1, 1, 1]

copyWithin

Array.prototype.copyWithin(targetStart, sourceStart, sourceEnd)

Массивы

Улучшения прототипа

find и findIndex

// Возвращает элемент либо undefined
Array.prototype.find(callback, thisArg])

// Возвращает индекс либо -1
Array.prototype.findIndex(callback, thisArg])

Массивы

Spread оператор

Вызовы функций

let arr = [1];
let missing = [2, 3, 4];

arr.push(...missing);

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

Массивы

Spread оператор

apply для конструктора

let parts = [2014, 9, 26];

console.log(new Date(...parts));

Destructive assignment

Destructive assignment

Массивы

ES5

var arr = [1, 2, 3];

var first = arr[0];
var second = arr[1];
var third = arr[2];

ES6

let arr = [1, 2, 3];
let [first, second, third] = arr;

// Перестановка без дополнительной переменной
[second, first] = [first, second];

Destructive assignment

Массивы

ES5

var nums = [1, 2, 3, 4, 5];

var head = nums[0];
var tail = nums.slice(1);
var fourth = nums[3];

ES6

let nums = [1, 2, 3, 4, 5];

let [head, ...tail] = nums;
// Можно игнорировать элементы
let [,,, fourth] = nums;

Destructive assignment

Массивы

ES5

var M = [[1, 2], [3, 4]];

var m12 = M[0][1];
var m21 = M[1][0];

ES6

let M = [[1, 3], [2, 4]];

// Любая вложенность
let [, m12, [, m22]] = M;

Destructive assignment

Объекты

ES5

var event = {
  name: 'WSD',
  desc: 'awesome'
};

var evtName = event.name;
var evtDesc = event.desc;

var name = event.name;
var desc = event.desc;

ES6

let event = {
  name: 'WSD',
  desc: 'awesome'
};

let {
  name: evtName,
  desc: evtDesc
} = event;

let { name, desc } = event;

Destructive assignment

Объекты

ES5

var deep = {
  arr: [
    'first',
    { second: 'second' },
    'third'
  ]
};

var second = deep.arr[1].second;
var third = deep.arr[2];

ES6

let deep = {
  arr: [
    'first',
    { second: 'second' },
    'third'
  ]
};

let {
  arr: [, { second }, third]
} = deep;

Destructive assignment

Значения по умолчанию

ES5

var missing = [][0];             // undefined

var found = missing || 1;        // 1

ES6

let [missing] = [];              // undefined

let [found = 1] = [];            // 1

Destructive assignment

Значения по умолчанию

ES5

var missing = {}['missing'];     // undefined

var found = missing || 1;        // 1

ES6

let { missing } = {};            // undefined

let { found = 1 } = {};          // 1

Destructive assignment

Применение

Определение параметров функций

function ajax({ url, method = 'GET', callback = () => {} }) {
  // Make a request
}

Destructive assignment

Применение

Множественные возвращаемые значения

function getDimensions() {
  return { width: 10, height: 5 };
};

let { width: w, height: h } = getDimensions();
console.log(w, h);                    // 10 5
function getCoordinates() {
  return [-10, 10];
};

let [x, y] = getCoordinates();
console.log(x, y)                     // -10 10

Модули

Модули

Сейчас

AMD — Require.js

Модули

ES6

  • Компактный декларативный синтаксис
  • Поддержка синхронной и асинхронной загрузки
  • Июль 2014 — синтаксис был окончательно утвержден

Модули

Импорт и экспорт по умолчанию

utils.js

export default function (msg) {
  console.log(msg);
};

main.js

import log from 'utils';

log('Hello, World!')

Модули

Именованный импорт и экспорт

utils.js

export function logMessage(msg) {
  console.log(msg);
}

function makeAssertion(expr, message) {
  console.assert(expr, message);
}

export { logMessage as log, makeAssertion as assert };

Модули

Именованный импорт и экспорт

math.js

export function isOdd(n) {
  return n % 2 > 0;
}

function randomInt(min, max) {
  return Math.floor(Math.random() * (max - min)) + min;
}

// Экспорт по умолчанию также именованный
export { randomInt as default };

Модули

Именованный импорт и экспорт

math.js

import { log, error } from 'utils';

// Импорт по умолчанию вместе с именованным
import random_int, { isOdd as is_odd } from 'math';

log(random_int(1, 5));

assert(is_odd(2), '2 это четное число!');

app.js

import { default as random_int } from 'math';

Модули

Импорт в качестве объекта

utils.js

export function log(msg) {
  console.log(msg);
}

export function assert(msg) {
  console.assert(expr, message);
}

main.js

import * as logger from 'logger';

logger.log('Hello, World!');
logger.assert(true === false, 'True это не false!')

Модули

Недосказанное

Модули

Использование

Изолированно:

И это все?!

Нет конечно!

  • Классы
  • Итераторы
  • Map + WeakMap
  • Set + WeakSet
  • Цикл for...of

И многое другое

ES7

Object.observe

Что используется сейчас:

Object.observe

Применение

Object.observe

let obj = {};

// Начать наблюдение
Object.observe(obj, function(changes) {
    changes.forEach(function({ type, name, oldValue }) {
        console.log(type, name, oldValue);
    });
});

// Оставить в покое
Object.unobserve(obj);

Object.observe

Применение

Можно наблюдать только интересующие изменения

let obj = {};
let interest = ['add', 'update', 'delete'];

// Начать наблюдение
Object.observe(obj, (changes) => {
  // Использовать изменения
}, interest);

Object.observe

Применение

Пользовательские события

let obj = {
  _foo: 'foo',

  set foo(value) {
    let event = {
      type: 'special-event',
      name: 'set-value',
      oldValue: this._foo,
      value: value
    };

    Object.getNotifier(this).notify(event);
  }
};

Object.observe

Применение

Пользовательские события

let interest = ['special-event'];

Object.observe(obj, (changes) => {
  console.log(changes[0]);
}, interest);

obj.foo = 'bar';

Object.observe

Поддержка

Что ещё?

Можно искать по запросу es7 strawman

И следить на esdiscuss.org

Поддержка

Где смотреть?

Таблица совместимости

Caniuse

Окружения

Современные браузеры

* с флагом --enable-javascript-harmony

Node.js

50 / 101 c флагом --harmony

Всё плохо?

Не совсем ...

Traceur

Плюсы:

6to5

Плюсы:

Не хочу использовать всё!

Разработка

Текстовые редакторы

Sublime Text

Webstorm

Vim

Инструменты

JSHint

Да!

JSCS

Да!

UglifyJS

Пока нет

Tern

Пока нет, но

Esprima

В разрабоке

Песочницы

Только ES6

Traceur REPL

ES6 Fiddle

Общего назначения

Traceur из коробки

Без встроенной поддержки Traceur

Кто использует?

Traceur

AngularJS 2.0

Ember.js

RSVP.js

Кто ещё?

В заключение

Так стоит ли использовать?

Будущее сейчас

и оно прекрасно

Вопросы?