ES2015 и не только

Узнаем и готовимся применять самое полезное

Для навигации используйте пробел или стрелки клавиатуры.

Esc для обзора слайдов.


За авторством Adevgo Ltd. Исходный код доступен на GitHub.

Что нам предстоит обсудить:

В июне 2015-го года был принят новый стандарт EcmaScript: ES2015, также известный как ES6.

let

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


var a = 2;
{
  let a = 3;
  console.log(a); // 3
  let a = 5;
  // TypeError: Identifier 'a' has already been declared
}
console.log(a); // 2
          
JS Bin

const

Другой формой объявления переменной с блочной областью видимости является ключевое слово const. Оно предназначено для объявления переменных (констант), значения которых доступны только для чтения. Это означает не то, что значение константы неизменно, а то, что идентификатор переменной не может быть переприсвоен.


{
  const B = 5;
  B = 10; // TypeError: Assignment to constant variable
  const ARR = [5, 6];
  ARR.push(7);
  console.log(ARR); // [5,6,7]
  ARR = 10; // TypeError: Assignment to constant variable
  ARR[0] = 3; // value is mutable
  console.log(ARR); // [3,6,7]
}
          
JS Bin

Обращаем внимание:

  • Когда дело касается поднятия переменных (hoisting) let и const, их поведение отличается от традиционного поведения var и function. И let и const не существуют до своего объявления.
  • Областью видимости let и const является ближайший блок.
  • При использовании const рекомендуется использовать ПРОПИСНЫЕ_БУКВЫ.
  • В const одновременно с объявлением переменной должно быть присвоено значение.
  • let (как и const) объявленные в цикле for (и for (in)) так же попадает в блочную область видимости этого цикла:

for (let i=0;i<10;i++) {/* ... */};
console.log(i); // → RefferenceError: i is not defined
          
JS Bin

Стрелочные функции
(Arrow functions)

Стрелочные функции представляют собой сокращённую запись функций в ES6. Стрелочная функция состоит из списка параметров ( ... ), за которым следует знак => и тело функции.


  // Classical Function Expression
  let addition = function(a, b) {
    return a + b;
  };

  // Implementation with arrow function
  let addition = (a, b) => a + b;
            
JS Bin

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


let arr = ['apple', 'banana', 'orange'];

let breakfast = arr.map(fruit => {
  return fruit + 's';
});

console.log(breakfast); // ['apples', 'bananas', 'oranges']
            
JS Bin

Стрелочные функции не просто делают код короче. Они тесно связаны с ключевым словом this и привязкой контекста. Поведение стрелочных функций с ключевым словом this отличается от поведения обычных функций с this. Каждая функция в JavaScript определяет свой собственный контекст this, но внутри стрелочных функций значение this то же самое, что и снаружи (стрелочные функции не имеют своего this).


function Person() {
  // The Person() constructor defines `this`
  // as an instance of itself.
  this.age = 0;

  setInterval(function growUp() {
    // In non-strict mode, the growUp() function
    // defines `this` as the global object, which
    // is different from the `this`
    // defined by the Person() constructor.
    this.age++;
  }, 1000);
}
var p = new Person();
              

setInterval(() => {
  setTimeout(() => {
    console.log(p.age);
  }, 1000);
}, 1000);
// 0
            
JS Bin

В ECMAScript 3/5 это поведение стало возможным изменить, присвоив значение this другой переменной.


function Person() {
  var self = this;
  self.age = 0;

  setInterval(function growUp() {
    // The callback refers to the `self` variable of which
    // the value is the expected object.
    self.age++;
  }, 1000);
}
            

setInterval(() => {
  setTimeout(() => {
    console.log(p.age);
  }, 1000);
}, 1000);
// 2 3 4...
            
JS Bin

Как сказано выше, внутри стрелочных функций значение this то же самое, что и снаружи, поэтому следующий код работает так, как от него и ожидается:


function Person() {
  this.age = 0;
  setInterval(() => {
    setTimeout(() => {
      this.age++;
      // `this` properly refers to the person object
    }, 1000);
  }, 1000);
}
var p = new Person();
            

setInterval(() => {
  setTimeout(() => {
    console.log(p.age);
  }, 1000);
}, 1000);
// 1 2 3 4...
            
JS Bin

const result = [1, 2, 3].map(num => num * 2);
console.log(result);
// [2, 4, 6]
            
JS Bin

const result = [1, 2, 3, 4].map((num, i) => num * 2 + i);
console.log(result);
// [2, 5, 8, 11]
            
JS Bin

NB

  • Стрелочные функции не могут быть использованы как конструкторы.
  • С фигурными скобками стрелочные функции требуют явного return.
  • this не может быть изменен с помощью .call или .apply и т.п.
  • В качестве arguments используются аргументы внешней "обычной" функции.

Параметры по умолчанию
(Default Function Parameters)

ES6 позволяет установить параметры по умолчанию при объявлении функции


let getFinPrice= (price, tax = 0.7) => price + price * tax;
getFinPrice(500); // 850
          
JS Bin

Spread / Rest оператор
(Spread / Rest Operator)

... оператор называют как spread или rest, в зависимости от того, как и где он используется. При использовании в любом итерируемом объекте (iterable), данный оператор "разбивает" ("spread") его на индивидуальные элементы:


function foo(x, y, z) {
  console.log(x, y, z);
}

let arr = [1, 2, 3];
foo(...arr); // 1 2 3
            
JS Bin

Другим распространённым использованием оператора ... является объединение набора значений в один массив. В данном случае оператор работает как "rest" ("соединяет с остальными элементами")


function foo(...args) {
  console.log(args);
}
foo(1, 2, 3, 4, 5); // [1, 2, 3, 4, 5]
            
JS Bin

function sum () {
  const nums = Array.prototype.slice.call(arguments);
  const multiplier = nums.shift();
  const base = nums.shift();
  const sum = nums.reduce((accum, num) => {
    return accum + num;
  }, base);
  return multiplier * sum;
}

const total = sum(2, 6, 10, 8, 9);
console.log(total);
// 66
            
JS Bin

function sum (multiplier, base, ...nums) {
  var sum = nums.reduce((accum, num) => accum + num, base);
  return multiplier * sum;
}

const total = sum(2, 6, 10, 8, 9);
console.log(total);
// 66
            
JS Bin

Расширение возможностей литералов объекта
(Object Literal Extensions)

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


function getCar(make, model, value) {
  return {
    // with property value shorthand syntax, you can omit
    // the property value if key matches variable name
    make,  // same as make: make
    model, // same as model: model
    value, // same as value: value
    // computed values now work with object literals
    ['make' + make]: true,
    // Method definition shorthand syntax omits
    // `function` keyword & colon
    depreciate() { this.value -= 2500; }
  };
}
            
JS Bin

let car = getCar('Kia', 'Sorento', 40000);
console.log(car);
// {
//   make: 'Kia',
//   model:'Sorento',
//   value: 40000,
//   makeKia: true,
//   depreciate: function()
// }
            
JS Bin

Восьмеричный и двоичный литералы
(Octal and Binary Literals)

В ES6 появилась новая поддержка для восьмеричных и двоичных литералов. Добавление к началу числа 0o или 0O преобразует его в восьмеричную систему счисления (аналогично, 0b или 0B преобразует в двоичную систему счисления).


let oValue = 0o10;
console.log(oValue); // 8

let bValue = 0b10;
console.log(bValue); // 2
          
JS Bin

Деструктуризация массивов и объектов
(Array and Object Destructuring)

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


function foo() {
  return [1, 2, 3];
}
let arr = foo(); // [1,2,3]

let [a, b, c] = foo();
console.log(a, b, c); // 1 2 3
            
JS Bin

function bar() {
  return {
    x: 4,
    y: 5,
    z: 6
  };
}
let { x: a, y: b, z: c } = bar();
console.log(a, b, c); // 4 5 6
            
JS Bin

const bar = {
  baz: "dat"
};

const { baz: foo } = bar;

console.log(foo);
// "dat"
            
JS Bin

const baz = {};
const { foo='bar' } = baz;

console.log(foo);
// "bar"
            
JS Bin

const {foo, bar: baz} = {foo: 0, bar: 1};

console.log(foo, baz);
// 0
// 1
            
JS Bin

const {foo: {bar}} = { foo: { bar: 'baz' } };

console.log(bar);
// "baz"
            
JS Bin

const {foo: {bar: deep}} = { foo: { bar: 'baz' } }

console.log(deep);
// "baz"
            
JS Bin

var {foo} = {}

console.log(foo);
// undefined
            
JS Bin

const {foo: {bar}} = {}

console.log(foo);
// TypeError: Cannot read property 'bar' of undefined
            
JS Bin

const [a, , b] = [0, 1, 2]

console.log(a, b);
// 0
// 2
            
JS Bin

let a = 13;
let b = 42;

[a, b] = [b, a]

console.log(a, b);
// 42
// 13
            
JS Bin

function foo ({ a=1, b=2 } = {}) {
  console.log(a, b);
}

const props = { a: 23 };

foo(props);
// 23
// 2

foo();
// 1
// 2
            
JS Bin

function getUrlParts (url) {
  var re =
    /^(https?):\/\/(example\.com)(\/articles\/([a-z0-9-]+))$/
  return re.exec(url)
}
const url = 'http://example.com/articles/some-article'
const parts = getUrlParts(url);
const [protocol,host,pathname,slug] = parts;
console.log(protocol, host, pathname, slug);
// 'http'
// 'example.com'
// '/articles/some-article'
// 'some-article'
            
JS Bin

const savedFile = {
  extension: 'jpg',
  name: 'repost',
  size: 14040
};

function fileSummary({name, extension, size}) {
   return `The ${name}.${extension} is of size ${size} B`;
}

const result = fileSummary(savedFile);

console.log(result);
// "The repost.jpg is of size 14040 B"
            
JS Bin

const companies = [
  'Google',
  'Facebook',
  'Yandex'
];

const [firstCompany, ...otherCompanies] = companies;

console.log(firstCompany, otherCompanies);
// "Google"
// ["Facebook", "Yandex"]
            
JS Bin

const companies = [
  { name: 'Google', location: 'Mountain View' },
  { name: 'Facebook', location: 'Menlo Park' },
  { name: 'Uber', location: 'San Francisco' }
];
const [{location: google}] = companies;
console.log(google);
// "Mountain View"
            
JS Bin

const points = [
  [4, 5],
  [10, 1],
  [0, 40]
];

const result = points.map(([x, y]) => {
  return { x, y }
});

console.log(result);
// [{x: 4, y: 5}, {x: 10, y: 1}, {x: 0, y:40}]
            
JS Bin

import React, { Component, PropTypes } from 'react';
            

import { includes } from 'lodash';
            
vs

import includes from 'lodash/includes';
            

Ключевое слово super для объектов

ES6 позволяет использовать метод super в (безклассовых) объектах с прототипами. Вот простой пример:


var parent = {
  foo() {
    console.log("Hello from the Parent");
  }
}
var child = {
  foo() {
    super.foo();
    console.log("Hello from the Child");
  }
}
Object.setPrototypeOf(child, parent);
child.foo(); // Hello from the Parent
             // Hello from the Child
            
JS Bin

Строковые шаблоны и разделители
(Template Literal and Delimiters)

ES6 предоставяляет более простой способ вставки значения переменной или результата выражения (т.н. "интерполяцию"), которые рассчитываются автоматически.

  • `${ ... }` используется для вычисления значения переменной/выражения.
  • `Обратные кавычки используются как разделитель.

let user = 'Kevin';
console.log(`Hi ${user}!`); // Hi Kevin!
            
JS Bin

Можно использовать свою функцию шаблонизации для строк.

Эта функция будет автоматически вызвана и получит в качестве аргументов строку, разбитую по вхождениям параметров ${…} и сами эти параметры.


const t = (template, ...vals) => [template, ...vals];

const foo = 42;
const bar = 13;

const [str, ...vals] = t`some text with ${foo} and ${bar}`;

console.log(str, vals);
// ["some text with ", " and ", ""]
// [42, 13]
            
JS Bin

Сравнение for...of и for...in

for...of используется для перебора в цикле итерируемых объектов, например, массивов.


let nicknames = ['di', 'boo', 'punkeye'];
nicknames.size = 3;
for (let nickname of nicknames) {
  console.log(nickname);
}
// di
// boo
// punkeye
            
JS Bin

for...in используется для перебора в цикле всех доступных для перебора (enumerable) свойств объекта.


let nicknames = ['di', 'boo', 'punkeye'];
nicknames.size = 3;
for (let nickname in nicknames) {
  console.log(nickname);
}
// 0
// 1
// 2
// size
            
JS Bin

for (let char of "Hello") {
  console.log(char); // H e l l o
}
            
vs

console.log(...'World'); // W o r l d
            
vs

const str = "Foo Bar";
let iterator = str[Symbol.iterator]();
while(true) {
  let result = iterator.next();
  if (result.done) break;
  console.log(result.value); // F o o " " B a r
}
            
JS Bin

Map

ES6 представляет новые структуры данных - Map и WeakMap. На самом деле, мы используем "Map" в JavaScript всё время. Каждый объект можно представить как частный случай Map.

Классический объект состоит из ключей (всегда в строковом виде) и значений, тогда как в Map для ключа и значения можно использовать любое значение (и объекты, и примитивы).


var myMap = new Map();

var keyString = "a string",
    keyObj = {},
    keyFunc = () => {};
            

// setting the values
myMap.set(keyString, "value associated with 'a string'");
myMap.set(keyObj, "value associated with keyObj");
myMap.set(keyFunc, "value associated with keyFunc");

myMap.size; // 3
            

// getting the values
myMap.get(keyString); // "value associated with 'a string'"
myMap.get(keyObj);    // "value associated with keyObj"
myMap.get(keyFunc);   // "value associated with keyFunc"
            
JS Bin

Метод set можно чейнить:


map
  .set('1', 'str1')
  .set(1, 'num1')
  .set(true, 'bool1');
            

При создании Map можно сразу инициализировать списком значений.


let map = new Map([
  ['1',  'str1'],
  [1,    'num1'],
  [true, 'bool1']
]);
            

Для проверки значений на эквивалентность используется алгоритм SameValueZero. Он аналогичен строгому равенству ===, отличие – в том, что NaN считается равным NaN. Поэтому значение NaN также может быть использовано в качестве ключа.

Этот алгоритм нельзя изменять или задавать свою функцию сравнения.

Методы для удаления записей:

  • map.delete(key) удаляет запись с ключом key, возвращает true, если такая запись была, иначе false.
  • map.clear() – удаляет все записи, очищает map.

Для проверки существования ключа:

  • map.has(key) – возвращает true, если ключ есть, иначе false.

Итерация:

  • map.keys() – возвращает итерируемый объект для ключей
  • map.values() – возвращает итерируемый объект для значений,
  • map.entries() – возвращает итерируемый объект для записей [ключ, значение], он используется по умолчанию в for..of.

WeakMap

WeakMap это Map, в котором ключи обладают неустойчивыми связями, что позволяет не мешать сборщику мусора удалять элементы WeakMap. Это означает, что можно не беспокоиться об утечках памяти.

Стоить отметить, что в WeakMap, в отличие от Map, каждый ключ должен быть объектом.

Для WeakMap есть только четыре метода: delete(ключ), has(ключ), get(ключ) и set(ключ, значение). Нет свойства size. Нельзя перебрать элементы итератором или forEach. Нет метода clear().


let w = new WeakMap();
w.set('a', 'b');
// Uncaught TypeError: Invalid value used as weak map key
            

var o1 = {},
  o2 = () => {},
  o3 = window;

w.set(o1, 37);
w.set(o2, "azerty");
w.set(o3, undefined);

w.get(o3); // undefined, because that is the set value

w.has(o1); // true
w.delete(o1);
w.has(o1); // false
            
JS Bin

Set

Объекты Set это коллекции уникальных значений. Дублированные значения игнорируются, т.к. коллекция должна содержать только уникальные значения. Значения могут быть примитивами или ссылками на объекты.


let mySet = new Set([1, 1, 2, 2, 3, 3]);
mySet.size; // 3
mySet.has(1); // true
mySet.add('strings');
mySet.add({ a: 1, b:2 });
            

mySet.forEach((item) => {
  console.log(item);
  // 1
  // 2
  // 3
  // 'strings'
  // Object { a: 1, b: 2 }
});
            

for (let value of mySet) {
  console.log(value);
  // 1
  // 2
  // 3
  // 'strings'
  // Object { a: 1, b: 2 }
}
            
JS Bin

Основные методы:

  • set.add(item) – добавляет в коллекцию item, возвращает set (чейнится).
  • set.delete(item) – удаляет item из коллекции, возвращает true, если он там был, иначе false.
  • set.has(item) – возвращает true, если item есть в коллекции, иначе false.
  • set.clear() – очищает set.

WeakSet

Аналогично WeakMap, объект WeakSet позволяет хранить объекты с неустойчивыми связями в коллекции. Объект в WeakSet уникален.


var ws = new WeakSet();
var obj = {};
var foo = {};

ws.add(window);
ws.add(obj);

ws.has(window); // true
ws.has(foo);    // false, foo has not been added to the set

ws.delete(window); // removes window from the set
ws.has(window);    // false, window has been removed
            
JS Bin

Классы в ES6

В ES6 представили новый синтаксис для классов. Здесь стоит отметить, что класс ES6 не представляет собой новую объектно-ориентированную модель наследования. Это просто синтаксический сахар для существующего в JavaScript прототипного наследования.

Класс в ES6 представляет собой просто новый синтаксис для работы с прототипами и функциями-конструкторами, которые мы привыкли использовать в ES5.

Функции, записанные с помощью ключевого слова static, используются для объявления статических свойств класса.


class Task {
  constructor() {
    console.log("task instantiated!");
  }
  showId() {
    console.log(23);
  }
  static loadAll() {
    console.log("Loading all tasks..");
  }
}
            

console.log(typeof Task); // function
let task = new Task(); // "task instantiated!"
task.showId(); // 23
Task.loadAll(); // "Loading all tasks.."
            
JS Bin

class Car {
  constructor (speed) {
    this.speed = speed
  }
}

class Tesla extends Car {
  constructor (speed) {
    super(speed * 2)
  }
}
            

var newCar = new Car(100);
var newTesla = new Tesla(120);

console.log(newCar.speed); // 100
console.log(newTesla.speed); // 240
            
JS Bin

extends и super в классах

В ES6 ключевое слово extends позволяет классу-потомку наследовать от родительского класса. Важно отметить, что конструктор класса-потомка должен вызывать super().

Также, в классе-потомке можно вызвать метод родительского класса с помощью super.имяМетодаРодителя().

Функции, записанные с помощью ключевого слова static, используются для объявления статических свойств класса.


class Car {
  constructor() {
    console.log("Creating a new car");
  }
}
            

class Porsche extends Car {
  constructor() {
    super();
    console.log("Creating Porsche");
  }
}
            

let c = new Porsche();
// Creating a new car
// Creating Porsche
            
JS Bin

О чём стоит помнить:

  • Объявления классов не поднимаются наверх (not hoisted). Сначала нужно объявить класс и только после этого использовать его, иначе будет ошибка ReferenceError.
  • Нет необходимости использовать ключевое слово function во время задания функций внутри определения класса.

Тип данных Symbol

Symbol это уникальный и неизменяемый тип данных, представленный в ES6. Целью Symbol является создание уникального идентификатора, к которому нельзя получить доступ.


var sym = Symbol("some optional description");
console.log(typeof sym); // symbol
            
JS Bin

Заметим, что использовать new вместе с Symbol(…) нельзя.

Если Symbol используется как свойство/ключ объекта, он сохраняется таким специальным образом, что свойство не будет показано при нормальном перечислении свойств объекта.


var o = {
  val: 10,
  [Symbol("random")]: "I'm a symbol",
};

console.log(Object.getOwnPropertyNames(o));
// ["val"]
console.log(Object.getOwnPropertySymbols(o));
// [Symbol(random)]
            

Чтобы извлечь символьные свойства объекта, нужно использовать Object.getOwnPropertySymbols(o)

JS Bin

Итераторы
(Iterators)

Итератор обращается к элементам коллекции по одному, в то же время сохраняя память о своей текущей позиции в этой коллекции. У итератора есть метод next(), который возвращает следующий элемент в последовательности. Этот метод возвращает объект с двумя свойствами: done (окончен ли перебор) и value (значение).

В ES6 есть метод Symbol.iterator, который определяет итератор для объекта по-умолчанию. При каждой необходимости перебора в цикле для объекта (например, в начале цикла for..of), его метод итератора вызывается без аргументов, и возвращённый итератор используется для того, чтобы получить значения для перебора.

Посмотрим на массив, который является перебираемым (iterable), и на итератор, который есть у массива для обработки его значений:


var arr = [11,12,13];
var itr = arr[Symbol.iterator]();

itr.next(); // { value: 11, done: false }
itr.next(); // { value: 12, done: false }
itr.next(); // { value: 13, done: false }

itr.next(); // { value: undefined, done: true }
            

Заметим, что можно написать собственный итератор через определение obj[Symbol.iterator]() с описанием объекта.

Tutor

Генераторы
(Generators)

Функции-генераторы представляют собой новую особенность ES6, которая позволяет функции создавать много значений в течение некоторого периода времени, возвращая объект (называемый генератором), который может быть итерирован для выброса значений из функции по одному за раз.

Функция-генератор возвращает итерируемый объект при своём вызове. Функция-генератор записывается с помощью знака * после ключевого слова function, а в теле функции должно присутствовать ключевое слово yield.


function *infiniteNums() {
  var n = 1;
  while (true) {
    yield n++;
  }
}

var numbers = infiniteNums(); // returns an iterable object

numbers.next(); // { value: 1, done: false }
numbers.next(); // { value: 2, done: false }
numbers.next(); // { value: 3, done: false }
            
Tutor

Каждый раз при вызове yield возвращённое значение становится следующим значением в последовательности.

Также заметим, что генераторы вычисляют свои возвращённые значения по запросу, что позволяет им эффективно представлять последовательности, затратные с точки зрения вычислений, или даже бесконечные последовательности.

Промисы
(Promises)

В ES6 появилась встроенная поддержка промисов. Промис это объект, который ждёт выполнения асинхронной операции, после которого (т.е. после выполнения) промис принимает одно из двух состояний: fulfilled (resolved, успешное выполнение) или rejected (выполнено с ошибкой).

Стандартным способом создания промиса является конструктор new Promise(), который принимает обработчик с двумя функциями как параметрами. Первый обработчик (обычно именуемый resolve) представляет собой функцию для вызова вместе с будущим значением, когда оно будет готово; второй обработчик (обычно именуемый reject) является функцией, которая вызывается для отказа от выполнения промиса, если он не может определить будущее значение.


var p = new Promise((resolve, reject) => {
  if (/* condition */) {
    resolve(/* value */);  // fulfilled successfully
  } else {
    reject(/* reason */);  // error, rejected
  }
});
            

Каждый промис обладает методом then, в котором есть два коллбэка. Первый коллбэк вызывается, если промис успешно выполнен (resolved), тогда как второй коллбэк вызывается, если промис выполнен с ошибкой (rejected).


p.then((val) => console.log("Promise Resolved", val),
       (err) => console.log("Promise Rejected", err));
            

При возвращении значения от then коллбэки передадут значение следующему коллбэку then.


var hello = new Promise((resolve, reject) => {
  resolve("Hello")
});

hello.then((str) => `${str} World`)
     .then((str) => `${str}!`)
     .then((str) => console.log(str)) // Hello World!
            
JS Bin

При возвращении промиса, успешно обработанное значение промиса пройдёт к следующему коллбэку, для того, чтобы эффективно соединить их вместе. Эта простая техника помогает избежать ада с коллбэками ("callback hell").


var p = new Promise((resolve, reject) => { resolve(1) });

var add1 = (val) => new Promise((resolve, reject) => {
  resolve(val + 1)
});

p.then(add1)
 .then(add1)
 .then((val) => console.log(val)); // 3
            
JS Bin

new Promise(resolve => resolve({ foo: 'bar' }))
  .then(result => console.log(result))
  // { foo: 'bar' }

new Promise((resolve, reject) =>
  reject(new Error('failed')))
  .catch(reason => {
    console.log(`${reason.name}: ${reason.message}`)
  });
  // "Error: failed"
            
JS Bin
Пример промисификации

Fetch

Метод fetch – это XMLHttpRequest нового поколения. Он предоставляет улучшенный интерфейс для осуществления запросов к серверу: как по части возможностей и контроля над происходящим, так и по синтаксису, так как построен на промисах.


fetch('/article/fetch/user.json')
  .then(function(response) {
    alert(response.headers.get('Content-Type'));
    // application/json; charset=utf-8
    alert(response.status); // 200

    return response.json();
   })
  .then(function(user) {
    alert(user.name); // admin
  })
  .catch( alert );
            
JS Bin
Визуализация

Дополнительно

Поддержка юникода


// same as ES5.1
"𠮷".length == 2
            

// new RegExp behaviour, opt-in ‘u’
"𠮷".match(/./u)[0].length == 2

            

// new form
"\u{20BB7}"=="𠮷"=="\uD842\uDFB7"
            

// new String ops
"𠮷".codePointAt(0) == 0x20BB7
            

// for-of iterates code points
for(var c of "𠮷") {
  console.log(c);
}
            
JS Bin

Модули


// 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);
}
            

// app.js
import ln, {pi, e} from "lib/mathplusplus";
alert("2π = " + ln(e)*pi*2);
            

Новые константы и методы


Number.EPSILON
Number.isInteger(Infinity) // false
Number.isNaN("NaN") // false
            

Math.acosh(3) // 1.762747174039086
Math.hypot(3, 4) // 5
Math.imul(Math.pow(2, 32) - 1, Math.pow(2, 32) - 2) // 2
            

"abcde".includes("cd") // true
"abc".repeat(3) // "abcabcabc"
"abccc".endsWith("ccc")) // true
"aaabc".startsWith("aaa") // true
            

Array.from(document.querySelectorAll('*'))
// Returns a real Array
Array.of(1, 2, 3)
// Similar to new Array(...),
// but without special one-arg behavior
[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]
["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"
            

Object.assign()

Функция Object.assign получает список объектов и копирует в первый target свойства из остальных.


Object.assign(target, src1, src2...)
            

const user = { name: "Вася" };
const visitor = { isAdmin: false, visits: true };
const admin = { isAdmin: true };

Object.assign(user, visitor, admin);

// user <- visitor <- admin
console.log( user );
// name: Вася, visits: true, isAdmin: true
            
JS Bin

Использованные материалы и рекомендации.