22 ноября в 19:00 состоится вебинар
"Как открыть для себя новые возможности через современную профессию Frontend разработчика"
Детальнее по ссылке.

17 Сен 2016

EcmaScript 6: новые возможности

Как известно, в июле 2015 года вышел долгожданный новый стандарт языка JavaScript.
В этой статье я хотел бы сделать краткий обзор новых возможностей, которые нам предоставляет ECMAScript 6 (ES6). В него было внесено много различных изменений. От достаточно серьезных — таких как работа с классами, до менее значительных, но очень удобных. Таких как стрелочные функции, например. Многие изменения настолько хороши, что, если вы начнете использовать новый стандарт, то вам никогда не захочется вернуться назад.

Для начала опишем новые особенности ES6, а потом некоторые паттерны их использования.
Что делать сейчас, когда еще не все новые возможности ES6 поддерживаются в браузерах? Как писать код ES6, который будет нормально сосуществовал с кодом, написанным на ECMAScript 5 (ES5)? В этом нам поможет компилятор BabelJS. С помощью этого инструмента код, написанный на ES6, и компилируется (преобразовывается) в “классический” стандарт ES5, в результате чего браузеры с легкостью его понимают.

 

Деструктивное присвоение или деструктуризация (Destructuring assignment).

Одно из самых интересных свойств в ES6 — это деструктивное присваивание (destructuring). Создадим объект и посмотрим как эта возможность работает.


<script>
var obj = {
one: 1,
two: 2
};
var {one,two} = obj;
console.log(two);
</script>

В ES5, чтобы переложить свойства объекта в переменную, нужно написать var one = obj.one;Соответственно такую операцию надо провести с каждым свойством объекта. В случае нового стандарта, как видите, все намного проще и код значительно короче. В примере выше мы создали две переменные одновременно, и они присвоили себе два свойства объекта попарно.
Причем эту операцию можно сделать одной строкой, что очень удобно, когда у вас есть большой объект с массой свойств. Для проверки нашего кода в консоль мы выводим значение переменной two. И действительно видим число 2. То есть, наш код отработал корректно.
Деструктивное присваивание работает и с массивами.


<script>
var numbers = ['one','two','three'];
var [ first, second ] = numbers;
console.log(first);
</script>

В этом примере консоль выведет нам строку 'one'. Согласитесь, что такой синтаксис достаточно удобный и логичный.
Вы также можете деструктивно присваивать переменные свойствам объекта.


<script>
var one = 1;
var obj = {
one,
second : 2
};
console.log(obj.one);
</script>

или

<script>
var one = 1, second = 2;
var obj = {
one,
second
};
console.log(obj.one);
console.log(obj.second);
</script>

И, как вы уже могли догадаться, в этом случае консоль выведет 1 и 2.
При создании объекта с помощью такого синтаксиса, автоматически определяется, что значение, прописанное при объявлении объекта, на самом деле является переменной, которая объявлена выше.
Ее имя становится ключом, а значение — соответственно значением этого ключа. Вы можете скопировать код, нажать в браузере F12 и в консоли самостоятельно убедиться в работоспособности этого кода. По крайней мере в Chome и Firefox эта конструкция должна работать уже сейчас.

Деструктуризация аргументов в функциях.

Этот же подход можно использовать и при работе с функциями.


<script>
function shapingModel({ width, height, size = 15}){
var model = {
width: width,
height: height,
size : size
}
console.log(model);
}
var params = {
width: 12,
height: 6
}
shapingModel(params);
//Object { width: 12, height: 6, size: 15 }
</script>

В данном примере кода вы видите способ, которым можно передать в функцию объект, а внутри функции принять данные не в виде объекта, а в виде отдельных аргументов.
Кроме того, поддерживаются так называемые «параметры по умолчанию». Есть возможность задать какое значение получит аргумент функции, если при вызове мы не передали ему никакого значения .
Следует учесть, что при передаче любого значения, кроме undefined, включая пустую строку, ноль или null, параметр считается переданным, и значение по умолчанию не используется.

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


<script>
function shapingModel({ width, height, size = 15}={}){
var model = {
width: width,
height: height,
size: size
}
console.log(model);
}
shapingModel();
//Object { width: undefined, height: undefined, size: 15 }
</script>

 

 

Функция ()=> (стрелочные функции).

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


<script>
var addition = function(a,b){
console.log(a + b);
return a + b;
}
addition(3,4);
</script>

А теперь перепишем данную функцию с использованием ES6.


<script>
var addition = (a,b) =>{
console.log(a + b);
return a + b;
}
addition(3,4);
</script>

В такой интерпретации изменения кажутся незначительными. Но если содержимое функции небольшое и вмещается в одну строчку, то именно здесь стрелочные функции и показывают всю свою мощь. Ключевое слово return можно упустить как и фигурные скобки. Таким образом запись получается очень компактной и элегантной. Разница с «классическим» подходом весьма ощутима.


<script>
var addition = (a,b) => a + b
addition(3,4);
</script>

Шаблонные строки (Template strings).

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


<script>
var name = 'Robert Jason';
var age = 43;
var today = function (){
return new Date();
}
var templateString = "Hi my name is " + name.substr(0, 6) + ". I'm" + age + " years old. Today is " + today();
console.log(templateString);
</script>

Если честно, мне всегда это не нравилось но элегантного решения не было. По этому раньше приходилось использовать разные шаблонизаторы. Или пользоваться встроенными возможностями фреймворка.
Сейчас все намного лучше.

Шаблонные строки избавляют нас от всего этого громоздкого кода.


<script>
var name = 'Robert Jason';
var age = 43;
var today = function (){
return new Date();
}
var templateString = `Hi my name ${name.substr(0, 6)}. I'm ${age} years old. Today is ${today()}`;
console.log(templateString);
</script>

Шаблонная строка создается с помощью обратных скобок `, а для того чтобы поместить переменную в строку, необходимо поставить перед ней знак $ и «завернуть» ее фигурными скобками. Так же можно переносить строки без любых знаков переноса.
Кроме того вы можете вызывать функцию прямо внутри фигурных скобок.
Улучшенная работа со строками, это одно из моих самых любимых нововведений.

 

Объявления переменных с помощью let.

В ES5 можно объявить переменную с помощью ключевого слава var. Как известно переменная доступна внутри функции в которой она объявлена. Если переменная объявлена за пределами функции, то она становится глобальной.


<script>
var data = 1;
console.log(data);
if(true) {
data = 2;
}
console.log(data);
</script>

В ES6 все немного изменилось. Появился новый способ объявления переменной с помощью ключевого слова let.
Переменные, объявленные с помощью let, имеют так называемую «блочную» области видимости, то есть они видны только внутри блока ограниченного фигурными скобками {}.
Перепишем наш пример, заменив var на let.


<script>
let data = 1;
console.log(data);
if(true) {
let data= 2;
}
console.log(data);
</script>

Как видите нижний console.log все еще выдает 1
Теперь у нас фактически 2 разные переменные. Одна внутри блока — одна снаружи.

Следует обратить внимание что к переменной, созданной с помощью let невозможно обратиться перед тем как она была объявлена.


<script>
console.log(data);
let data = 1;
// ReferenceError: can't access lexical declaration `data' before initialization
</script>

Этот код выдаст ошибку.

 

Классы в EcmaScript 6.

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


<script>
class Car{
constructor(name){
this.wheels = 4;
this.name = name;
}
drive(){
console.log('Car is on road');
}
stop(){
console.log('Car is stoped');
}
}
var bmw = new Car('M5');
bmw.drive();
bmw.stop();
console.log(bmw.name);
console.log(bmw.wheels);
</script>

Думаю, многие ждали такой реализации наследования в JavaScript. Выглядит очень элегантно.
Если необходимо унаследовать наш класс от родительского или базового, можно воспользоваться ключевым словом extend. Раньше, если вам необходимо было вызвать метод родителя из наследника, приходилось прибегать ко всяким ухищрениям, которые выглядели странно и не всегда были понятны.
Теперь все намного проще. Наконец то можно использовать вызов метода родителя через super
Посмотрим что получилось в результате:


<script>
class ElectroCar extends Car {
constructor(){
super()
}

drive(){
super.drive()
console.log('Tesla is using battery to drive');
}
}
var tesla = new ElectroCar();
tesla.drive();
tesla.stop();
</script>

Мы рассмотрели некоторые из наиболее интересных возможностей которые нам предоставляет ES6. Многое из этого уже работает в современных браузерах таких как Chrome и Firefox.
Но, конечно же, это не все возможности нового стандарта.

На нашем курсе «Понятный JavaScript» мы изучаем глубоко и системно не только чистый JavaScript но и возможности ES6 в том числе.
Если вы хотите разбираться в этом всем на высшем уровне присоединяйтесь к нам.
Старт курса 22 сентября.