Введение в ES6



Введение в ES6

0 0


es6-attestate


On Github DenisPronin / es6-attestate

Введение в ES6

О стандарте

  • Название стандарта - ECMAScript
  • Текущая версия - ES-2015 (ES6)
  • ES5 - был в 2009 году.

Browser Support

https://kangax.github.io/compat-table/es6/

Browser Support

Babel

https://babeljs.io/

Преобразует код из ES-2015 в ES5 ES5 поддерживается везде

Легко добавляется в состав системы сборки frontend'a (Gulp, Grunt, Webpack ...)

Browser Support with Babel

Фичи ES6

Объявление переменной с let

Область видимости переменной let — блок {}

ES5

function showApplesCount() {
    var apples = 5;
    if (true) {
        var apples = 10;
        alert(apples); // 10
    }
    alert(apples); // 10
}

ES6

function showApplesCount() {
    let apples = 5; // (*)
    if (true) {
        let apples = 10;
        alert(apples); // 10
    }
    alert(apples); // 5
}

Объявление переменной с let

let видна только после объявления

ES5

alert(a); // undefined
var a = 5;

ES6

alert(a); // ReferenceError
let a = 5;

let в цикле

ES5

for(var i=0; i<10; i++) {
    /* … */
}
alert(i); // 10

ES6

for(let i=0; i<10; i++) {
    /* … */
}
alert(i); // i is not defined

const

Задаёт константу, которую нельзя менять

const apple = 5;
apple = 10; // ошибка

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

Особый синтаксис присваивания, при котором можно присвоить массив или объект сразу нескольким переменным, разбив его на части

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

ES5

var coord = [150, 200];
var x = coord[0];
var y = coord[1];
alert(x); // 150
alert(y);  // 200

ES6

let [x, y] = [150, 200];
alert(x); // 150
alert(y);  // 200

Деструктуризация. Оператор Spread

let [first, last, ...rest] = "Юлий Цезарь Император Рима".split(" ")
alert(first); // Юлий
alert(last);  // Цезарь
alert(rest);  // ["Император", "Рима"]

Деструктуризация. Значения по умолчанию

let [first='First', last] = [];
alert(first); // First
alert(last);  // undefined

Деструктуризация. Объекты

let {var1, var2} = {var1:…, var2:…}

let options = {
    title: "Меню",
    width: 100,
    height: 200
};

let {title, width = 0, height:h} = options;
alert(title);  // Меню
alert(width);  // 100
alert(h); // 200

Строки в js

var value = 'value';
var str = 'some string with ' + value + ' and ' +
    'multiline'

Шаблоны в строках

Обратные кавычки ``

  • Разрешён перевод строки
    alert(`моя
    многострочная
    строка`);
  • Можно вставлять выражения при помощи ${…}
    let apples = 2;
    let oranges = 3;
    
    alert(`Sum of: ${apples} + ${oranges} = ${apples + oranges}`);
    // Sum of  2 + 3 = 5

Строки. Новые методы

  • str.includes(s) — проверяет, включает ли одна строка в себя другую, возвращает true/false.
  • str.endsWith(s) — возвращает true, если строка str заканчивается подстрокой s.
  • str.startsWith(s) — возвращает true, если строка str начинается со строки s.
  • str.repeat(times) — повторяет строку str times раз.

Строки в ES-2015

Функции

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

function func(title = "Title", width = getWidth(), height = 200) {
    alert(`${title} ${width} ${height}`);
}

func("Меню"); // Меню 100 200

Функции

Оператор spread вместо arguments

function showName(firstName, lastName, ...rest) {
    alert(`${firstName} ${lastName} - ${rest}`);
}

showName("Юлий", "Цезарь", "Император", "Рима");
// Юлий Цезарь - Император,Рима

Функции

Деструктуризация в параметрах

let options = {
    title: "Меню",
    width: 100,
    height: 200
};

function showMenu({title, width, height}) {
    alert(`${title} ${width} ${height}`); // Меню 100 200
}
showMenu(options);

Функции

  • Свойство name

    function f() {}
    f.name === "f" // true
  • Функция, объявленная в блоке, видна только в этом блоке.

Функции

Стрелочный синтаксис

ES5

var positive = numbers.filter(function(num) {
    return num > 0
});

ES6

var positive = numbers.filter(num => num > 0);

Объекты

Короткое свойство

let name = "Вася";
let isAdmin = true;

let user = {
    name,
    isAdmin
};
alert( JSON.stringify(user) );
// {"name": "Вася", "isAdmin": true}

Объекты

Вычисляемые свойства

let propName = "firstName";

let user = {
    [propName]: "Вася"
};

Объекты

Методы объекта

let name = "Вася";
let user = {
    name,
    // вместо "sayHi: function()
    sayHi() {
        alert(this.name);
    }
};

user.sayHi(); // Вася

Объекты

__proto__ и super

let animal = {
    walk() {
        alert("I'm walking");
    }
};

let rabbit = {
    __proto__: animal,
    walk() {
        super.walk(); // I'm walking
    }
};

rabbit.walk();

Объекты. Новые методы

  • Object.assign(target, src1, src2...)
  • Object.is(value1, value2)

Классы

Синтаксис

class Название [extends Родитель]  {
    constructor
    методы
}

Классы

class User {
    constructor(name) {
        this.name = name;
    }

    sayHi() {
        alert(this.name);
    }
}

let user = new User("Вася");
user.sayHi(); // Вася

Классы

Геттеры и сеттеры

class User {
    constructor(firstName, lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
   }

    get fullName() {
        return `${this.firstName} ${this.lastName}`;
    }

    set fullName(newValue) {
        [this.firstName, this.lastName] = newValue.split(' ');
    }
}

let user = new User("Вася", "Пупкин");
alert( user.fullName ); // Вася Пупков
user.fullName = "Иван Петров";
alert( user.fullName ); // Иван Петров

Классы

Статические свойства

class User {
    constructor(firstName, lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    static createGuest() {
      return new User("Гость", "Сайта");
    }
};

let user = User.createGuest();

Классы

Наследование

class Animal {
  constructor(name) {
    this.name = name;
  }

  walk() {
    alert(`${this.name} walk`);
  }
}
class Rabbit extends Animal {
    walk() {
        super.walk();
        alert("...and jump!");
    }
}

new Rabbit("Вася").walk();

Классы

private и protected свойства

Модули

  • AMD (Require.js)
  • Common.js (Node.js)

Модули: export

Ключевое слово export можно ставить:

  • Перед объявлением переменных, функций и классов
    export let one = 1;
  • Отдельно, при этом в фигурных скобках указывается, что именно экспортируется
    let one = 1;
    let two = 2;
    export {one as once, two as twice};

Модули: import

import {one, two} from "./nums";

ES6. Коллекции

  • Map
  • Set
  • WeakSet
  • WeakMap

Map

Object. Ключ - только строка

Map. Ключ - произвольный тип

let map = new Map([
    ['string',  'str1'],
    [1,    'num1']
]);
map.set(true, 'bool1');
map.size() // 3

Map. Методы

  • map.delete(key)
  • map.clear()
  • map.has(key)

Для итерации используются:

  • map.keys() - по ключам
  • map.values() - по значениям
  • map.entries() - возвращает массив [ключ, значение]

Map

let recipeMap = new Map([
    ['огурцы', '500 гр'],
    ['помидоры', '300гр'],
]);

for(let key of recipeMap.keys()) {
    alert(key); // огурцы, помидоры
}

for(let amount of recipeMap.values()) {
    alert(amount); // 500 гр, 350 гр
}

for(let entry of recipeMap)
    alert(entry); // ['огурцы', '500 гр'] ...
}

Set

Коллекция множества уникальных значений

let set = new Set();

let vasya = {name: "Вася"};
let petya = {name: "Петя"};
let dasha = {name: "Даша"};

set.add(vasya);
set.add(petya);
set.add(dasha);
set.add(vasya);
set.add(petya);

alert( set.size ); // 3
set.forEach( user => alert(user.name ) ); // Вася, Петя, Даша

Set. Методы

  • set.add(item)
  • set.delete(item)
  • set.has(item)
  • set.clear()

WeakSet и WeakMap

Особый вид коллекций не препятствующий сборщику мусора удалять свои элементы.
Работают только на запись и чтение по ключу

Ограничения:

  • Нет свойства size
  • Нельзя итерировать
  • Нет метода clear

WeakMap. Пример

let activeUsers = [
    {name: "Vasia"},
    {name: "Petia"},
    {name: "Masha"}
];

let weakMap = new WeakMap();

weakMap.set(activeUsers[0], 1);
weakMap.set(activeUsers[1], 2);
weakMap.set(activeUsers[2], 3);

alert( weakMap.get(activeUsers[0]) ); // 1

activeUsers.splice(0, 1); // в weakMap теперь только 2 элемента
activeUsers.splice(0, 1); // в weakMap теперь только 1 элемент

Цикл for..of

20 лет назад

for (var index = 0; index < myArray.length; index++) {
    console.log(myArray[index]);
}

Цикл for..of

ES5

myArray.forEach(function (value) {
    console.log(value);
});

for (var index in myArray) {    // bad
    console.log(myArray[index]);
}

Цикл for..of

ES6

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

Плюсы

  • Лаконичный
  • Нет недостатков for..in
  • Работает с break, continue и return
  • Работает не только с массивами, но и с объектами, строками, Map, Set

Promise

Callback-hell

Promise

Синтаксис

var promise = new Promise(function(resolve, reject) {
// В ней можно делать любые асинхронные операции,
// А когда они завершатся — нужно вызвать одно из:
// resolve(результат) при успешном выполнении
// reject(ошибка) при ошибке
})
promise.then(onFulfilled, onRejected)

Promise

Пример

let promise = new Promise((resolve, reject) => {
    setTimeout(() => resolve("result"), 1000);
});

promise.then(
    result => {
        alert("Fulfilled: " + result); // result - аргумент resolve
    },
    error => {
        alert("Rejected: " + error); // error - аргумент reject
    }
);

Promise

Цепочки

httpGet('/article/promise/user.json')
  // 1. Получить данные о пользователе в JSON и передать дальше
  .then(response => {
    let user = JSON.parse(response);
    return user;
  })
  // 2. Получить информацию с github
  .then(user => {
    return httpGet(`https://api.github.com/users/${user.name}`);
  })
  // 3. Вывести аватар
  .then(githubUser => {
    githubUser = JSON.parse(githubUser);
    let img = new Image();
    img.src = githubUser.avatar_url;
    document.body.appendChild(img);
  })
  .catch(error => {
    alert(error);
  });

Генераторы

Новый вид функций.

Могут приостанавливать своё выполнение, возвращать промежуточный результат и далее возобновлять его позже, в произвольный момент времени

function* generateSequence() {
    yield 1;
    yield 2;
    return 3;
}

let generator = generateSequence();

let one = generator.next(); // {value: 1, done: false}
let two = generator.next(); // {value: 2, done: false}
let three = generator.next(); // {value: 3, done: true}

Генераторы

Пример: Написание "плоского" асинхронного кода.

  • Генератор yield'ит не просто значения, а промисы
  • Cпециальная функция execute запускает генератор:
    • Последовательно вызывает next и возвращает промис
    • Когда промис выполняется, то результат промиса возвращается в генератор при следующем вызове next
  • Последнее значение генератора (done:true) возвращается во внешний код, например через промис

Генераторы

Пример: Написание "плоского" асинхронного кода.

function* showUserAvatar() {
  let user = yield fetch('/article/generator/user.json');
  let githubUser = yield fetch(`https://api.github.com/users/${user.name}`)
  return githubUser.avatar_url;
}

function execute(generator, yieldValue, callback) {
  let next = generator.next(yieldValue);
  if (!next.done) {
    next.value.then(
      result => execute(generator, result, callback),
      err => generator.throw(err)
    );
  } else {
    callback(next.value);
  }
}

execute( showUserAvatar(), null, callback );

Выводы

  • Очень объемный стандарт
  • Среди фич много синтаксического сахара
  • Но также много фундаментальных фич (let, modules, promises...)
  • Постепенно все перейдет на ES6
  • Можно юзать сейчас благодаря Babel

Ссылки

https://learn.javascript.ru/es-modern - отличный обзор
https://hacks.mozilla.org/category/es6-in-depth/ - книга про es6. (en) Есть много переводов глав из этой книги
http://exploringjs.com/es6/ - ещё книга про es6
http://es6-features.org/ - сниппеты es6 vs es5

Вопросы?

Спасибо за внимание!

Введение в ES6