[Перевод] Обзор ES6 в 350 пунктах. Часть первая
Моя серия заметок ES6 in Depth, состоящая из 24 записей, описывает большинство синтаксических изменений и нововведений в ES6. В этой публикации я подведу итог всего изложенного в предыдущих статьях, чтобы дать возможность посмотреть еще раз на всё вместе. Также я добавил ссылки на мой блог, чтобы в случае необходимости сразу же можно было посмотреть подробнее.
Я слышал, вы любите маркированные списки, так что вот вам статья со списком, который состоит из нескольких сотен элементов.
Для начала приведу оглавление, чтобы было понятно, о чем пойдет речь. Очевидно, что оглавление – это также ненумерованный список. Обратите внимание: если хотите глубже вникнуть в эту тему, прочтите весь цикл статей и самостоятельно «поковыряйте» код ES6.
Содержание
● Введение
● Инструментарий
● Assignment Destructing
● Spread Operator и Rest Parameters
● Стрелочные функции
● Шаблонные строки
● Литералы объектов
● Классы
● Let и Const
● Символы
● Итераторы
● Генераторы
● Промайсы
● Maps
● WeakMaps
● Sets
● WeakSets
● Прокси
● Reflection
● Number
● Math
● Array
● Object
● Строки и Unicode
● Модули
Извините за такое длинное оглавление. Начинаем.
Введение
● ES6 (также известен как Harmony, es-next, ES2015) – последняя и окончательная спецификация языка.
● Окончательная спецификация ES6 была утверждена в июне 2015 года (следовательно, ES2015).
● Будущие версии языка будут называться согласно шаблону ES[YYYY], например ES2016 для ES7.
o Ежегодный релиз-цикл, необратимые изменения начинают действовать со следующего релиза.
o Так как ES6 появился раньше, чем это решение, большинство из нас всё еще называет его ES6.
o Начиная с ES2016 (ES7), мы должны использовать шаблон ES[YYYY], чтобы ссылаться на новые версии.
o Главная причина использования такого шаблона именования – оказание давления на производителей браузеров с целью как можно более быстрого внедрения последних обновлений.
Инструментарий
● Чтобы использовать ES6 сегодня, вам потребуется JavaScript-to-JavaScript транспайлер.
● Транспайлеры пришли и останутся, потому что:
o они предоставляют возможность компилировать код новой версии языка в код старой версии;
o мы будем транспайлить ES2016 и ES2017 в ES6 и т. д., когда браузерная поддержка станет лучше;
o нам потребуется улучшенный функционал source mapping;
o на сегодняшний день это самый надежный способ запускать ES6 код в продакшн (несмотря на то, что браузеры поддерживают ES5).
● У babel (транспайлера) есть киллер-фича: человекочитаемый вывод (human-readable output).
● Используйте babel, чтобы транспайлить ES6 в ES5 для статических сборок.
● Используйте babelify, чтобы внедрить babel в свой grunt, gulp или npm run процесс сборки.
● Используйте nodejs весии 4.x.x или выше – там есть весьма приличная поддержка ES6 (спасибо v8).
● Используйте babel-node с любой версией node.js – он будет транспайлить модули в ES5.
● В babel есть разрастающаяся экосистема, которая уже поддерживает ES2016 и некоторые плагины.
● Прочитайте A Brief History of ES6 Tooling.
Assignment Destructuring
● var {foo} = pony то же, что var foo = pony.foo.
● var {foo: baz} = то же, что var baz = pony.foo.
● Можно задавать значения по умолчанию, var {foo='bar'} = baz вернет foo: 'bar', если baz.foo является undefined.
● Можно затащить сколько угодно свойств, под псевдонимами или без них:
o var {foo, bar: baz} = {foo: 0, bar: 1} даст foo: 0 и baz: 1.
● Можно пойти дальше: var {foo: {bar}} = { foo: { bar: 'baz' } } даст bar: 'baz'.
● Этому тоже можно назначить псевдоним: var {foo: {bar: deep}} = { foo: { bar: 'baz' } } даст вам deep: 'baz'.
● Свойства, которые не были найдены, по-прежнему возвращают undefined var {foo} = {}.
● Вложенные свойства, которые не были найдены, возвращают ошибку var {foo: {bar}} = {}.
● Это также работает для массивов, [a, b] = [0, 1] вернет a: 0 и b: 1.
● Можно пропускать элементы в массиве, [a,, b] = [0, 1, 2], получаем a: 0 и b: 2.
● Переменные можно менять местами, не прибегая к помощи третьей “aux” переменной, [a, b] = [b, a].
● Можно также использовать destructuring в параметрах функций:
o присваивание значений по умолчанию function foo (bar=2) {};
o эти значения могут также быть и объектами function foo (bar={ a: 1, b: 2 }) {};
o можно деструктурировать bar полностью: function foo ({ a=1, b=2 }) {};
o если ничего не было передано, по умолчанию получаем пустой массив: function foo ({ a=1, b=2 } = {}) {}.
Прочитайте ES6 JavaScript Destructuring in Depth.
Spread Operator и Rest Parameters
● Rest parameters – это как arguments, только лучше.
o сигнатура метода объявляется как function foo (...everything) {};
o everything – это массив со всеми параметрами, переданными в foo;
o можно присвоить имя нескольким параметрам перед ...everything, например: function foo (bar, ...rest) {};
o эти параметры будут исключены из ...rest;
o ...rest должен быть последним параметром в списке.
● Spread operator – это даже лучше, чем магия, он также обозначается при помощи … синтаксиса:
o отменяет необходимость apply при вызове методов, fn(...[1, 2, 3]) – то же, что fn(1, 2, 3);
o упрощенная конкатенация: [1, 2, ...[3, 4, 5], 6, 7];
o позволяет слепить массивоподобные элементы или коллекции в массивы [...document.querySelectorAll('img')];
o также полезен при destructing [a,, ...rest] = [1, 2, 3, 4, 5] возвращает a: 1 и rest: [3, 4, 5];
o делает new + .apply простым, new Date(...[2015, 31, 8]).
● Прочитайте ES6 Spread and Butter in Depth.
Стрелочные функции
● Лаконичный способ объявить функцию param => returnValue.
● Полезно при функциональном программировании, [1, 2].map(x => x * 2).
● Есть несколько разных способов использования (займет некоторое время, чтобы выработать привычку):
○ p1 => expr отлично подходит, если параметр один;
○ p1 => expr имеет неявный оператор return для выражения expr;
○ чтобы неявно вернуть объект, нужно обернуть его в круглые скобки () => ({ foo: 'bar' }), иначе получите ошибку;
○ круглые скобки необходимы, когда у вас 0, 2 или больше параметров () => expr or (p1, p2) => expr;
○ фигурные скобки в правой части представляют блок кода, в котором может содержаться несколько инструкций () => {};
○ при использовании такого синтаксиса неявного return нет, его нужно писать () => { return 'foo' }.
● Нельзя статически давать стрелочной функции имя, но тесты производительности намного лучше для большинства методов без имени.
● Стрелочные функции привязаны к лексическому окружению:
○ this это тот же контекст this, что и в родительском лексическом окружении;
○ this нельзя изменить при помощи .call, .apply, или похожих методов “reflection”-типа.
● Прочитайте ES6 Arrow Functions in Depth.
Шаблонные строки
● Строки можно объявлять при помощи обратных кавычек (`) в дополнение к одинарным и двойным.
● Строки с обратными кавычками являются шаблонными строками.
● Шаблонные строки могут быть многострочными.
● Шаблонные строки позволяют производить промежуточные вычисления `ponyfoo.com is ${rating}`, где rating – это переменная.
● Можно использовать любое валидное js-выражение для вычисления, например: `${2 * 3}` или `${foo()}`.
● Можно использовать помеченные шаблоны, чтобы изменить логику вычисления промежуточных значений:
○ добавить префикс fn к fn`foo, ${bar} and ${baz}`;
○ fn вызывается единожды с template, ...expressions;
○ template – это ['foo, ', ' and ', ''], а expressions – это [bar, baz];
○ результат fn становится значением шаблонной строки;
○ возможные примеры использования: очистка вводимых выражений от лишних данных, парсинг параметров и т. д.
● Шаблонные строки практически во всем лучше строк, обернутых в одинарные или двойные кавычки.
● Прочитайте ES6 Template Literals in Depth.
Литералы объектов
● Вместо { foo: foo }, можно писать просто { foo } – сокращенная форма записи пары свойство–значение.
● Вычисляемые имена свойств: { [prefix + 'Foo']: 'bar' }, где prefix: 'moz' возвращает { mozFoo: 'bar' }.
● Нельзя одновременно пытаться использовать две предыдущих особенности, запись {[foo]} – невалидна.
● Определения методов можно сделать более лаконичными при помощи следующего синтаксиса: { foo () {} }.
● Смотрите также секцию Object.
● Прочитайте ES6 Object Literal Features in Depth.
Классы
● Не «традиционные» классы, а синтаксический сахар поверх механизма наследования прототипов.
● Синтаксис похож на объявление объектов class Foo {}.
● Методы экземпляра new Foo().bar объявляются при помощи упрощенного синтаксиса литералов объекта class Foo { bar () {} }.
● Статические методы – Foo.isPonyFoo() – нуждаются в префиксе, ключевом слове static class Foo { staticisPonyFoo () {} }.
● Метод конструктора class Foo { constructor () { /* initialize instance */ }.
● Прототипное наследование с упрощенным синтаксисом class PonyFoo extends Foo {}.
● Прочитайте ES6 Classes in Depth.
Let и Const
● let и const – это альтернативы var при объявлении переменных.
● let имеет блочную область видимости, а не лексическую, по отношению к родительской функции.
● let поднимается в верхнюю часть блока, в то время как var поднимается в верхнюю часть функции.
● «Временная мертвая зона» или просто ВМЗ:
○ начинается в начале блока, в котором происходит объявление let foo;
○ заканчивается в том месте кода, где происходит объявление let foo (здесь «подъем» не имеет значения);
○ попытки доступа или определения foo внутри ВМЗ (до того, как будет выполнена инструкция let foo) приведут к ошибке;
○ помогает сократить число загадочных багов, в которых значение переменной претерпевает изменения раньше, чем происходит ее объявление.
● const также имеет блочную область видимости, «подъем» и следует семантике ВМЗ.
● Переменные const должны быть объявлены при помощи инициализатора const foo = 'bar'.
● Определение const после инициализации побуждает тихую ошибку (или не тихую – в строгом режиме).
● Переменные const не делают переменную неизменяемой:
○ const foo = { bar: 'baz' } значит, что foo всегда будет ссылаться на объект в правой части выражения;
○ const foo = { bar: 'baz' }; foo.bar = 'boo' не бросит исключение.
● Определение переменной с таким же именем – бросит.
● Предназначен для того, чтобы исправлять ошибки, когда вы переопределяете переменную и теряете ссылку на первоначальный объект.
● В ES6 функции имеют блочную область видимости:
○ предотвращают утечку данных через механизм «всплытия» { let _foo = 'secret', bar = () => _foo; };
○ не ломают пользовательский код в большинстве ситуаций и, как правило, являются тем, что вам нужно.
● Прочитайте ES6 Let, Const and the “Temporal Dead Zone” (TDZ) in Depth.