ECMAScript 6 — версия языка JavaScript, стандарт которой утвердился в 2015 году.
Для использования возможностей ES6 необходим либо запуск скриптов в окружении, поддерживающем эту версию языка, либо использования специальных программ — транспайлеров, например, Babel (пример работы Babel — тут). Поддержку возможностей ES6 для различных окружений можно посмотреть здесь.
Стандарт добавляет два нового вида переменных: let и const. Исользуются они так же, как и переменные var:
let myMoney = 0.05;
const humanStupidity = Infinity;
Но данные виды переменных имеют следующие особенности использования:
Обычно для констант, содержащих примитивы, имя задается прописными буквами, а для констант-объектов — строчными.
При написании кода обычно руководствуются подходом: объявлять максимум переменных как const, а те, которые будут меняться, — как let.
Деструктуризация — специальный синтаксис присваивания для задания значений массивам и объектам.
При использовании квадратных скобок можно присвоить элементы массива переменным, находящимся на соответсвующих местах:
let suitcase = ["cap", "t-shirt", "tie"];
let [item1, item2, item3] = suitcase;
console.log(item1); // cap
console.log(item2); // t-shirt
console.log(item3); // tie
При необходимости можно пропустить какие-либо перменные, тем самым отбросив ненужные элементы массива:
let suitcase = ["cap", "t-shirt", "tie"];
let [, myFavouriteItem] = suitcase;
console.log(myFavouriteItem); // t-shirt
Для того, чтобы получить элементы массива, если мы заранее не знаем их количества, мы можем использовать оператор spread (троеточие), который поместит оставшиеся элементы в указанную переменную:
let suitcase = ["cap", "t-shirt", "tie", "socks"];
let [item1, ...restItems] = suitcase;
console.log(item1); // cap
console.log(restItems); // ["t-shirt", "tie", "socks"]
Если элементов в массиве меньше, чем запрашиваемых переменных, то "лишние" переменные получат undefined:
let suitcase = ["cap", "t-shirt"];
let [,,item3] = suitcase;
console.log(item3); // undefined
Чтобы предупредить такое поведение мы можем указать значение, которое примет переменная, если соответсвующего ей элемента массива не существует. Такое значение называется значением по умолчанию:
let suitcase = ["cap", "t-shirt"];
let [,,item3="pants"] = suitcase;
console.log(item3); // pants
В качестве значения по умолчанию может быть не только примитив, но и объект или выражение:
let suitcase = ["cap", "t-shirt"];
let [,,item3=3+1, item4=Math.round(1.49)] = suitcase;
console.log(item3); // 4
console.log(item4); // 1
Деструктуризация работает и с объектами. Для передачи значений необходимо, чтобы совпадали не позиции переменных, а их названия с названиями свойств массива:
let suitcase = {
item1: "cap",
item2: "t-shirt"
};
let {item1, item2} = suitcase;
console.log(item1); // cap
console.log(item2); // t-shirt
Если необходимо получить переменную с именем, отличным от названия свойства, то новое имя указывают через двоеточие внутри деструктуризирующих скобок:
let suitcase = {
item1: "cap",
item2: "t-shirt"
};
let {item1: vintageItem, item2: modernItem} = suitcase;
console.log(vintageItem); // cap
console.log(modernItem); // t-shirt
Как и в случае деструктуризации массива можно указать параметры по умолчанию:
let suitcase = {
item1: "cap",
item2: "t-shirt"
};
let {item1: blackItem, item3: whiteItem="pants", greyItem="boa"} = suitcase;
console.log(blackItem); // cap
console.log(whiteItem); // pants
console.log(greyItem); // boa
Если необходимо произвести деструктуризацию для уже объявленных переменных, то такую деструктуризацию оборачивают в круглые скобки, чтобы интерпретатор не воспринял такую конструкцию без let как логический блок.
Даже если объект для "разбора" достаточно сложен, его можно деструктуризировать сразу:
let suitcase = {
item1: "cap",
item2: "t-shirt",
socks: {
count: 2,
color: "#000"
},
box: ["toothbrush", "toothpaste"]
};
let {item1, socks:{count: socksCount=5}, box:[,boxedItem]} = suitcase;
console.log(item1); // cap
console.log(socksCount); // 2
console.log(boxedItem); // toothpaste
Как и в строгом режиме, в ES6 нет однозначной привязки между аргументами функции и arguments.
В ES6 появилась возможность задавать параметры по умолчанию для функций:
function plusTwo(num=0) {
return num + 2;
}
console.log(plusTwo(2)); // 4
console.log(plusTwo()); // 2
Параметр по умолчанию используется для отсутствующего или равного undefined аргумента.
Параметры по умолчанию могут быть значениями:
function plusTwo(num=1+Math.ceil(2*Math.random())) {
return num + 2;
}
console.log(plusTwo()); // 4
console.log(plusTwo()); // 5
Функция параметра по умолчанию вызовется только в том случае, если этот параметр понадобится.
Подобно деструктуризации, оператор spread может собирать аргументы функции:
function sum(num, ...rest) {
console.log(num); // 1
console.log(rest); // [2, 3, 4]
return 42;
}
sum(1, 2, 3, 4);
При использовании оператора троеточие не в конце списка аргументов возникнет ошибка, т.к. он собирает "оставшиеся" параметры, и после него уже никаких параметров быть не может.
Оператор ... может использоваться как для преобразования списка аргументов в массив, так и наоборот. Например, для передачи массива не как одного аргумента, а как набора аргументов:
let nums = [1,2,3,4];
console.log( Math.max(...nums) );
При передаче аргумента-объекта его также можно деструктуризовать "на месте":
let suitcase = {
item1: "cap",
item2: "t-shirt",
socks: {
count: 2,
color: "#000"
},
box: ["toothbrush", "toothpaste"]
};
function whatIsInSuitcase({item1, socks:{count}}) {
console.log("I have " + item1 + " and " + count + " socks in my suitcase."); // I have cap and 2 socks in my suitcase.
}
whatIsInSuitcase(suitcase);
Тут же можно указать параметры по умолчанию для каждого из свойств. Необходимо только, чтобы объект для деструктуризации существовал:
function whatIsInSuitcase({item1="nothing", socks:{count=1}}) {
console.log("I have " + item1 + " and " + count + " socks in my suitcase."); // I have nothing and 1 socks in my suitcase.
}
whatIsInSuitcase({socks:{}});
Чтобы запускать функцию без параметра нужно указать ожидаемую структуру объекта в параметре по умолчанию:
function whatIsInSuitcase({item1="nothing", socks:{count=42}} = {socks:{}}) {
console.log("I have " + item1 + " and " + count + " socks in my suitcase."); // I have nothing and 42 socks in my suitcase.
}
whatIsInSuitcase();
Подобно let и const функция, объявленная внутри блока, не видна за его пределами, даже если она объявлена как Function Declaration. Чтобы добиться интерпретации такого кода как кода ES6, нужно указать "use strict".
В ES6 функциям добавили "стрелочный" синтаксис:
let plusTwo = (num) => num + 2;
console.log( plusTwo(2) ); // 4
Для функции без аргументов используются пустые скобки:
let return42 = () => 42;
console.log( return42() ); // 42
Если нужно поместить в тело функции несколько строк кода, то используют фигурные скобки:
let return42 = () => {
let start = 10;
start *= 4;
start += 2;
return start;
};
console.log( return42() ); // 42
Особенностью стрелочных функций также является отсутсвие собственного this, что делает удобных их использование в функциях callbackах:
let suitcase = {
type: "vintage",
items: ["pants", "cap", "t-shirt"],
showList: function() {
this.items.forEach((v) => console.log(this.type + " : " + v) );
}
};
suitcase.showList();
Из-за отсутствия this стрелочные функции нельзя использовать в качестве конструкторов.
Стрелочные функции не имеют arguments.
Был добавлен синтаксис строковых шаблонов:
let str = `my string`;
Особенности:
При создании строкового шаблона можно задать имя тега, если в коде встретиться функция с таким именем, то она выполнится и в качестве параметров ей передадутся все строки и все переменные шаблона:
let str = lol`${2} + ${2} is ${2 + 2} \n sure`;
function lol (literals, ...values) {
console.log(literals); // ["", " + ", " is ", " ↵ sure"
console.log(values); // [2, 2, 4]
}
Массив literals так же содержит свойство raw, в котром литералы содержатся в исходном виде.
Тег шаблонизации может изменить шаблон и вернувшийся результат присвоить строке.
Для строк добавлены новые методы:
Использование фигурных скобок в записях с '\u' позволяет указать в качестве кода символа более, чем четырехзначное число.
При создании объектов можно воспользоваться синтаксисом, внешне похожим на "деструктуризацию наоборот":
let item1 = "pants";
let item2 = "cap";
let suitcase = {
item1,
item2
};
console.log(suitcase);
Заключив имя свойства в квадратные скобки, можно использовать выражения для вычиления их названий:
let propName = "item1";
let suitcase = {
[propName]: "t-shirt"
};
console.log(suitcase);
К методу Object.getPrototypeOf(obj) добавили сеттер прототипа Object.setPrototypeOf(obj, newProto). Так же разрешен прямой доступ к объекту __proto__.
Метод assign копирует в свой первый аргумент-объект свойства из всех остальных аргументов-объектов. Все последующие свойства перезаписывают предыдущие.
Метод is сравнивает значения двух своих аргументов, почти как это делает ===, но имеет особенности: с помощью такого сравнения NaN равен NaN.
Был добавлен более короткий синтаксис создания методов объекта:
let suitcase = {
item1: "tie",
open() {
console.log("Suitcase is opened");
}
};
В таком же стиле можно добавлять гетеры и сеттеры свойств:
let suitcase = {
myState: "opened",
get state() {
return `Suitcase is ${this.myState}`;
}
};
console.log(suitcase.state);
Таким же образом можно добавить метод с вычисляемым названием:
let myMethod = "close";
let suitcase = {
item1: "tie",
[myMethod]() {
console.log("Suitcase is closed");
}
};
В ES6 с помощью ключевого слова super в методе объекта можно получить свойство его прототипа:
let item = {
volume: 10
};
let suitcase = {
__proto__: item,
volume: 20,
info() {
console.log(`My new volume is ${this.volume},
my ex one is ${super.volume}`);
}
};
suitcase.info();