Как стать автором
Обновить

Ecmascript 6 — что можно использовать уже сейчас

JavaScript *


Примечание: статья расчитана в основном на не-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++ на помойку, это значит что овладеть джаваскриптом стало еще легче, за счет удобного синтаксиса и более стабильного поведения.
Теги:
Хабы:
Всего голосов 67: ↑48 и ↓19 +29
Просмотры 60K
Комментарии Комментарии 39