
Примечание: статья расчитана в основном на не-Javascript программистов — иногда я буду вдаваться в объяснения достаточно основных вещей, но надеюсь будет полезна и тем, кто просто не успел ознакомиться с большинством нововведений ES6.
Как известно, стандарт Ecmascript 6 собираются опубликовать в июне 2015. Но так как многое уже имплементировано в современный браузерах, почему-бы не начать использовать это прямо сейчас?
Поскольку jsFiddle и аналоги ES6 не поддерживают, буду использовать es6fiddle для примеров. К сожалению, не все в нем можно показать из-за багов. При отсутствии ссылок на es6fiddle рекомендую копировать сниппеты кода в консоль современного браузера и выполнять их — для наглядности. Рекомендую крайний стабильный Firefox (версия 33 на момент написания статьи) — там все работает «из коробки».
Так как изменений очень много, опишу субъективно самые важные.
let и scope — переменные с блочной областью видимости (block scope)
Одна из самых раздражающих/непонятных для начинающих JS-программистов вещей это область видимости переменных в JS. Пример:
for(var i=0; i<10; i++){ } console.log(i);
В большинстве языков подобный код выкинет ошибку что i не дефинирована, но в JS в консоль выведется число «10». Причина в том, что в JS используется hoisting — то есть декларации всех используемых переменных переносятся в начало функции (и соответственно i доступна вне блока for). Именно поэтому советуют декларировать все переменные в начале функции — все равно они будут туда перенесены при выполнении кода.
В ES6 можно написать:
for(let j=0; j<10; j++){ } console.log(j);
В этом коде область видимости j ограничена блоком for. Больше нет смысла декларировать переменные в начале функции!
Про const говорить особо нечего — это декларация константы, при повторном п��исвоении значения выбрасывает TypeError (в strict mode).
Пример:
function setConst(){ "use strict"; const xx = 10; xx = 11; console.log(xx); } setConst();
Ссылок на примеры нет, так как на данный момент block scope в es6fiddle не поддерживается. Ждем фиксов.
Arrow functions
Если вы использовали лямбды в C#, вы сразу узнаете синтаксис (это не случайность — он был взят именно оттуда).
Как писали раньше:
function SomeClass() { var self = this; //самый простой способ сохранить контекст нужного объекта self.iter = 0; setInterval(function() { self.iter++; console.log('current iteration: ' + self.iter); }, 1000); } var sc = new SomeClass();
В ES6 можно гораздо проще:
function SomeClass() { this.iter = 0; setInterval(() => { this.iter++; console.log('current iteration: ' + this.iter); }, 1000); } var sc = new SomeClass();
es6fiddle
Как видно, arrow function не создает своего контекста, так что this будет указывать на контекст функции, в которой вызван код.
Пример с параметрами:
let numList = [1,2,3]; let doubleNumList = numList.map(n => n*2); console.log(doubleNumList);
es6fiddle
Сравните, насколько более громоздкий старый метод:
let numList = [1,2,3]; let doubleNumList = numList.map(function(n){ return n*2; }); console.log(doubleNumList);
Классы
Старый способ эмулировать классы в JS выглядит как-то так:
function Vehicle(topSpeed){ this.topSpeed = topSpeed; this.printTopSpeed = function(){ console.log('Top speed:'+this.topSpeed+' km/h'); } } var myVehicle = new Vehicle(50); myVehicle.printTopSpeed();
jsFiddle
«Традиционное» наследование как в Java/C# можно также эмулировать через протопипную модель (код приводить не буду, чтобы не раздувать статью).
В ES6 появляются «настоящие» классы:
class Vehicle { constructor(topSpeed){ this.topSpeed = topSpeed; } printTopSpeed(){ console.log('Top speed:'+this.topSpeed+' km/h'); } } class Bicycle extends Vehicle { constructor(topSpeed, wheelSize, bicycleType, producedBy){ super(topSpeed); this.wheelSize = wheelSize; this.bicycleType = bicycleType; this.producedBy = producedBy; } static wheelCount(){ return 2; } get bikeInfo(){ return this.producedBy + ' ' + this.bicycleType + ' bike'; } printBicycleType(){ console.log('Type:'+this.bicycleType+' bike'); } } var myBike = new Bicycle(40,622,'road','Trek'); myBike.printTopSpeed(); myBike.printBicycleType(); console.log('Bicycles have '+Bicycle.wheelCount()+' wheels'); console.log(myBike.bikeInfo);
es6fiddle
Думаю, что код выше в комментариях не нуждается. Как видно, в классах можно дефинировать геттеры и статические методы (но не поля), синтаксис интуитивно понятен. Стоит отметить, что тело класса (class body) всегда интерпретируется в strict mode. Ну и конечно никто не заставляет оголтелых адептов прототипного наследования менять свои привычки — классы это вообщем-то синтаксический сахар поверх старой модели.
Destructuring assignment
Напоследок, небольшая но интересная фича, которая облегчает присвоение значений. Пример:
function getFirstPrimeNumbers(){ return [2,3,5]; } var [firstPrime, secondPrime, thirdPrime] = getFirstPrimeNumbers(); console.log(thirdPrime); //5 //обмен значений (value swap) var [x,y] = [1,2]; console.log('x:'+x, 'y:'+y); //x:1 y:2 [x,y] = [y,x]; console.log('x:'+x, 'y:'+y); //x:2 y:1
es6fiddle
Теперь можно обменивать значения без временной переменной, что сокращает код.
Немного более сложный пример:
var myBook = { title: "Surely You're Joking, Mr. Feynman!", author:{ firstName: 'Richard', lastName: 'Feynman', yearBorn: 1918 } }; function getTitleAndAuthorsLastName({ title, author: { lastName } }){ return 'title: '+ title + ' last name:'+lastName; } console.log(getTitleAndAuthorsLastName(myBook));
es6fiddle
Как использовать?
Предвижу возмущение — как видно из все той же таблицы, кое-где ES6 сразу не работает. Хром, к примеру, не поддерживает большинство вещей из списка, если не включен флаг Enable Experimental JavaScript. Выход — использовать Traceur, компилятор из ES 6 в ES 5.
Именно он используется в es6fiddle, кстати. На странице в гитхабе есть инструкция по использованию. Вкратце для браузера:
1. Подключаем 2 JS файла:
<script src="https://google.github.io/traceur-compiler/bin/traceur.js"></script> <script src="https://google.github.io/traceur-compiler/src/bootstrap.js"></script>
2. Добавляем для поддержки эксперементальных фич ES6:
<script> traceur.options.experimental = true; </script>
3. Пишем код в script тегах с типом module:
<script type="module"> let a = 10; </script>
Заключение
Надеюсь, что данная статья смогла показать, что Javascript на данный момент развился в достаточно серьезный язык программирования (хоть и с местами странным поведением). Это не значит что надо выкидывать любимые Java/C#/C++ на помойку, это значит что овладеть джаваскриптом стало еще легче, за счет удобного синтаксиса и более стабильного поведения.
