ES6

Материал из Национальной библиотеки им. Н. Э. Баумана
Последнее изменение этой страницы: 03:18, 23 января 2016.
ECMASrcipt 2015
Класс языка:

мультипарадигменный: функциональный, прототипно-ориентированный, императивный

Появился в:

1995

Автор:

Брендан Эйх

Расширение файлов:

.js

Выпуск:

ECMAScript 6 (17 июня 2015)

Система типов:

слабая динамическая

Диалекты:

JavaScript, JScript, ActionScript, JScript .NET, QtScript

Испытал влияние:

Self, Си, Scheme, Perl, Python, Java, AWK

Повлиял на:

Objective-J

Сайт:

ecmascript.org

ES6 или ECMAScript 6, так же известная как ECMAScript 2015, является последней версией стандарта ECMAScript. ES6 является значительным дополнением к языку и первым обновлением с тех пор, как ES5 был стандартизирован в 2009 году. Цели создания ECMAScript 2015 включают в себя обеспечение поддержки расширяемых приложений, написание библиотек и использование ECMAScript в качестве компилятора для других языков. Некоторые значительные улучшения включают в себя модули, объявление классов, лексические области видимости переменных, итераторы и генераторы, Promises для асинхронного программирования, деструктуризацию по паттерну, оптимизацию хвостовой рекурсии и другие.

Стрелочные функции

Стрелочные функции являются удобным сокращением для обычных функций при помощи => синтаксиса. Такой синтексис идентичен для аналогичных функций в C#, Java 8 и CoffeeScript. Стрелочные функции поддерживают блоки операторов и блоки выражений, которые возвращают значение. В отличие от обычных функций, они разделяют лексический контекст this с окружающим кодом.

// Блок выражений
var odds = evens.map(v => v + 1);

// Блок операторов
nums.forEach(v => {
  if (v % 5 === 0)
    fives.push(v);
});

// Контекст this
var bob = {
  _name: "Bob",
  _friends: [],
  printFriends() {
    this._friends.forEach(f =>
      console.log(this._name + " knows " + f));
  }
}

Классы

Классы широко обсуждаемая возможность в ES6. Некоторым кажется, что они противоречат прототипной природе JavaScript, другие считают, что они понижают входной барьер для новичков и тех, кто раньше программировал на других языках, а также помогают писать расширяемые приложения.

Классы основаны на ключевых словах 'class и constructor.

Пример:

class Vehicle {
   constructor(name) {
      this.name = name;
      this.kind = 'vehicle';
   }
   getName() {
      return this.name;
   }   
}

// Создание экземпляра класса
let myVehicle = new Vehicle('rocky');

Чтобы создать экземпляр класса, необходимо использовать ключевое слово new. Чтобы унаследовать базовый класс, используют extends. Из класса-наследника можно получить доступ к конструктору ил методам базового класса с помощью метода super.

class Car extends Vehicle {
   constructor(name) {
      super(name);
      this.kind = 'car'
   }
}

let myCar = new Car('bumpy');

myCar.getName(); // 'bumpy'
myCar instanceof Car; // true
myCar instanceof Vehicle; //true

Promises

Promises ("обещания") являются инструментом для асинхронного программирования. Технически они представляют собой значение, которое может стать доступным в будущем. Существуют различные реализации этой технологии в других JavaScript-библиотеках.

function timeout(duration = 0) {
    return new Promise((resolve, reject) => {
        setTimeout(resolve, duration);
    })
}

var p = timeout(1000).then(() => {
    return timeout(2000);
}).then(() => {
    throw new Error("hmm");
}).catch(err => {
    return Promise.all([timeout(100), timeout(200)]);
})

Шаблонизация строк

Шаблонизированные строки это строковые литералы, которые позволяют выполнять выражения. Можно использовать многострочность и строковую интерполяцию.

// Basic literal string creation
`In JavaScript '\n' is a line-feed.`

// Multiline strings
`In JavaScript this is
 not legal.`

// String interpolation
var name = "Bob", time = "today";
`Hello ${name}, how are you ${time}?`

Деструктуризация

Деструктуризация позволяет привязывать данные при совпадении паттерна. Поддерживается для массивов и объектов. Деструктуризация устойчива к ошибкам и во многом похожа на поиск поля в объеке: foo["bar"] - возвращает undefined в случае, если что-то пошло не так.

var [a, b] = [1, 2]
var [a, b, ...rest] = [1, 2, 3, 4, 5]
var [foo, [[bar], baz]] = [1, [[2], 3]]
var {a, b} = {a:1, b:2}

var o = {p: 42, q: true};
var {p, q} = o;

// Присваивание при деструктуризации
// можно сделать и без объявления переменных
({a, b} = {a:1, b:2});

Let + Const

Ключевое слово let объявляет область видимости для локальной переменной в пределах блока и инициализирует её. Выгодно отличается от ключевого словаvar, которое объявляет переменную глобально или локально внутри функции вне зависимости от области видимости блока.

Ключевое слово const создает ссылку на переменную, доступную только для чтения. Это не означает, что само значение становится неизменным, но идентификатор переменной не может быть переопределен.

function f() {
  {
    let x;
    {
      const x = "sneaky";  // переменная в области видимости блока
      x = "foo"; // ошибка - изменение константы
    }
    // ошибка, переменная уже объявлена в этом блоке
    let x = "inner";
  }
}

Iterators + For..Of

Iterable протокол позволяет JavaScript объектам определять или кастомизировать итерационное поведение, а именно какие значения перебираются в цикле for..of. Некоторые встроенные типы по умолчанию являются итерируемыми и имеют стандартное поведение, например Array или Map, в то время как другие типы (например Object) не являются.

Для того чтобы быть iterable, объект обязан имплементировать @@iterator метод. Это означает, что объект (или один из объектов из цепочки прототипов) должен иметь свойство Symbol.iterator key: функцию без аргументов, которая возвращает объект согласно протоколу.

Iterator протокол определяет стандартный способ создания последовательности значений (конечной или бесконечной). Объект является итератором в том случае, если он имплементирует метод 'next() со следующим определением:

Свойство Значение
next Функция без аргументов, которая возвращает объект с двумя полями:
  • done (boolean)
    • true если итератор дошел до конца последовательности. В этом случае значение value вернет такое же значение.
    • false если итератор смог вернуть следующий элемент последовательности.
  • value - любое JavaScript значение. Может быть проигнорировано, если done: true.

Пример:

let fibonacci = {
  [Symbol.iterator]() {
    let pre = 0, cur = 1;
    return {
      next() {
        [pre, cur] = [cur, pre + cur];
        return { done: false, value: cur }
      }
    }
  }
}

for (var n of fibonacci) {
  if (n > 1000)
    break;
  console.log(n);
}

Generators

Генераторы упрощают написание итераторов с помощью function* и yield. Функция, объявленная как function*, возвращает экземпляр Generator. Генераторы являются подтипом итераторов, которые имеют дополнительное методы next и throw. В теле генератора ключевое слово yield используется, чтобы остановить выполнение функции изнутри. Чтобы продолжить выполнение или запустить генератор с самого начала, потребуется внешнее воздействие.

function *foo(x) {
    var y = 2 * (yield (x + 1));
    var z = yield (y / 3);
    return (x + y + z);
}

var it = foo( 5 );

console.log( it.next() );       // { value:6, done:false }
console.log( it.next( 12 ) );   // { value:8, done:false }
console.log( it.next( 13 ) );   // { value:42, done:true }

Модули

JavaScript не имеет встроенной поддержки для модулей, но сообщество создало впечатляющие решения этой проблемы. Два особенно важных (и к сожалению несовместимых) стандарта - CommonJS Modules и Asynchronous Module Definition (AMD). Целью модулей в ECMAScript 6 является создание формата, который был бы удобен как для пользователей CommonJS, так и для поклонников AMD.

// lib/math.js
export function sum(x, y) {
  return x + y;
}
export var pi = 3.141593;
// app.js
import * as math from "lib/math";
alert("2π = " + math.sum(math.pi, math.pi));
// otherApp.js
import {sum, pi} from "lib/math";
alert("2π = " + sum(pi, pi));
// lib/mathplusplus.js
export * from "lib/math";
export var e = 2.71828182846;
export default function(x) {
    return Math.log(x);
}

Ресуры