Если вы еще не работали с JavaScript или работали с предыдущими версиями JavaScript, есть большая вероятность, что вы не изучили новые функции и синтаксис, добавленные в JavaScript ES6. Вы можете знать ES6 по ECMASCRIPT 6 или ES2015, но все они одинаковы.

В этом посте мы рассмотрим новые функции и синтаксис, предоставляемые ES6.

Оглавление

Занятия

Классы не новы в JavaScript, они давно стали частью JavaScript. ES6 представляет новый способ написания классов.

Вот пример традиционного функционального класса:

function Starks(name) {
   this.name = name;
   this.houseName = 'House Stark';
   this.seat = 'Winterfell';
}
Starks.prototype.getHouseName = function() {
   return this.houseName;
}
var starks = new Starks();
console.log('Seat: ' + starks.seat);
// Seat: Winterfell
console.log('House: ' + starks.getHouseName());
// House: House Stark

При использовании ES6 мы можем использовать ключевое слово class для создания класса:

class Starks {
   constructor(name) {
     this.name = name;
     this.houseName = 'House Stark';
     this.seat = 'Winterfell';
   }
   getHouseName() {
     return this.houseName;
   }
}
const starks = new Starks();
console.log('Seat: ' + starks.seat);
// Seat: Winterfell
console.log('House: ' + starks.getHouseName());
// House: House Stark

Мы также можем создавать статические методы для классов с ключевым словом static.

class Starks {
   static words() {
     return 'Winter is coming!';
   }
}
console.log(Starks.words()); // 'Winter is coming!'

Мы также можем расширить классы, используя ключевое слово extend

class Jon extends Starks {
   getHouseName() {
     return 'House Targaryen';
   }
}
const jon = new Jon();
console.log(jon.getHouseName()); // House Targaryen

Пусть и константа

let и const — два новых ключевых слова для объявления переменных в ES6. В отличие от var, let и const заблокированы в области действия, а не в области действия функции.

Не понял? Позволь мне объяснить:

function foo() {
  if (true) {
      var functionScoped = "I'm function scoped";
      let blockScoped = "I'm block scoped"; // Same applies to const
  }
  console.log(functionScoped);
  // I'm function scoped
  
  console.log(blockScoped);
  // Uncaught ReferenceError: blockScoped is not defined
}

foo();

Здесь к переменной functionScoped можно получить доступ за пределами блока if, поскольку var имеет область действия функции, поэтому переменная functionScoped может использоваться во всей функции foo. В то время как переменная blockScoped доступна только в объявленном блоке, переменная blockedScoped может использоваться только в блоке if.

Итак, мы получили разницу между var и let и const, но в чем разница между let и const? Хотите знать, почему для объявления переменных используются два ключевых слова?

Тогда давайте к этому:

Разница между let и const заключается в том, что если переменная собирается изменить свое значение и собирается переназначить значение, используйте let иначе const. Значение должно быть указано во время объявления переменной const. Если вы попытаетесь переназначить значение переменной const, будет выброшена ошибка (Uncaught TypeError: Assignment для постоянной переменной).

Пример:

const PI = 3.14;
// const is used here as value of PI is never going to change
const r = 5; // Assuming value of r will be set dynamically
let area = 0;
// Reassigning the let variable as r is a positive value
if (r > 0) area = PI * r * r;
console.log('Area: '+ area);

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

const dob = {};
dob.date = 30;
dob.month = 8;

Здесь мы не переназначаем значение константной переменной dob, мы добавляем свойство к константной переменной dob, которая не переназначается и, следовательно, не вызывает ошибки.

Стрелочные функции

Стрелочные функции также известны как толстые функции или лямбда-функции.

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

function square(num) {
   return num * num;
}
// here (num) is the argument of the function
// and => specifies the starting of function body.
const square = (num) => {
     return num * num;
}
// Note that if a function has only one argument, () can be avoided.
const square = num => {
     return num * num;
}
// Note that if a function body has only one statement
// that returns a value, we can use shorthand like this.
const square = num => num * num;
// All of the functions declaration above
// will produce same output.
// Some other sugar syntax for arrow functions
// A function without an argument must have ()
// Same applies to functions without an argument and function body
const foo = () => 'bar';
// Returning an object from arrow shorthand
// The return object is wrapped in () as {} means function body. const foo = () => ({ foo: 'bar' });

Стрелочные функции имеют лексический this. что такое лексическое this? Вы могли заметить такой код: var self = this; или var that = this;. Теперь мы можем избежать этого, используя стрелочные функции.

// ES5
this.nums = [1,2,3,4,5,6,7,8,9];
this.odds = [];
var that = this;
// ES5 way 1
this.nums.forEach(function (num) {
     if (num % 2 || num === 1) that.odds.push(num);
});
// ES5 way 2
this.nums.forEach(function (num) {
     if (num % 2 || num === 1) this.odds.push(num);
}, this);
// ES5 way 3
this.nums.forEach(function (num) {
     if (num % 2 || num === 1) this.odds.push(num);
}.bind(this));
console.log('Odds: ' + this.odds);
// ES6
this.nums = [1,2,3,4,5,6,7,8,9];
this.odds = [];
this.nums.forEach((num) => {
     if (num % 2 || num === 1) this.odds.push(num);
});
console.log('Odds: ' + this.odds);

В способах 2 и 3 ES5 мы видим, что использовали это вместо того, так в чем же преимущество использования стрелочных функций по сравнению с привязкой this к функции? Привязка this к функции — медленная операция, и, привязывая this к функции, мы выполняем привязку каждый раз, когда эта функция вызывается. Это означает, что это влияет на производительность и может быть решено с помощью стрелочных функций. Родительская область this передается стрелочным функциям, которые мы называем лексическими this.

Деструктурирование

Деструктуризация помогает нам извлекать вложенные данные из массивов или объектов.

const starks = [{ name: 'Arya' }, { name: 'Jon' }, { name: 'Sansa' }];
// Destructuring of array
const [arya, jon, sansa] = starks;
// I love Arya and I only want her from starks then
const [arya] = starks;
// Well arya wants her sister Sansa but not Jon then,
const [arya, , sansa] = starks; // Skip a index by keeping it blank
console.log(arya); // { name: 'Arya' }
// Destructuring of object
const { name } = arya;
console.log(name); // Arya
// Aliasing a property
// (just in case we already have a variable named `'name'`)
const { name: aryaName } = arya;
console.log(aryaName); // Arya
// Accessing nested values
const res = { data: { records: [1, 2] } };
const { data: { records } } = res; console.log(records); // [1, 2]

Расширенные литералы объектов

Расширенные литералы объектов, такие как сокращения значений свойств, вычисляемые ключи свойств и сокращения методов.

Вот пример сокращенного значения свойства:

// ES5
var data = [{ something: 'Important' }];
return { data: data};
// ES6
const data = [{ something: 'Important' }];
// Here { data } is same as { data: data }
return { data };

Вот пример вычисляемых ключей свойств:

// ES5
var name = 'Arya';
var starks = {};
starks['' + name] = { house: 'Stark', ability: 'many-faced gods' };
console.log(starks);
// { Arya: { house: 'Stark', ability: 'many-faced gods' } }

// ES6
const name = 'Arya';
const starks = { [name]: { house: 'Stark', ability: 'many-faced gods' } };
console.log(starks);
// { Arya: { house: 'Stark', ability: 'many-faced gods' } }

Мы уже использовали сокращение метода в классе. Вот еще один пример:

// ES5
var calculations = {
    square: function(num) {
      return num * num;
    }
}


// ES6
const calculations = {
    // No : function
    square(num) {
      return num * num;
    }
}

Шаблонные литералы

Литералы шаблонов — это строковые литералы, которые позволяют использовать встроенные выражения. Эти выражения могут быть чем угодно, что может иметь вычисляемое значение.

В то время как строки заключаются в одинарные или двойные кавычки, литералы шаблонов заключаются в обратные кавычки (``). Литералы шаблонов могут иметь заполнители. Заполнители обозначаются знаком доллара, за которым следуют фигурные скобки ${expression}.

Некоторые примеры:

console.log(`This is plain string`);

const a = 5, b = 10;
console.log('The number is ' + a + '.'); // The number is 5.
console.log(`The number is ${a}.`); // The number is 5.

console.log('The addition of a and b is ' + (a + b) + '.');
// The number is 15.
// Simple expression
console.log(`The addition of a and b is ${a + b}.`);
// The number is 15.

function add(a, b) {
   return a + b;
}

// Calling a function
console.log(`The addition of a and b is ${add(a, b)}.`);
// The number is 15.

// Using ternary operator.
console.log(`The addition of the numbers a and b is ${add(a, b) % 2 === 0 ? 'even' : 'odd'}.`);

// Multi line 

// Without template literals
console.log('Text from line 1\n' +
'Text from line 2');
// Text from line 1
// Text from line 2

// With template literals
console.log(`Text from line 1
Text from line 2`);
// Text from line 1
// Text from line 2

Итераторы

ES6 предоставляет множество встроенных функций для перебора массивов. Эти функции работают быстро и позволяют избежать потенциальных ошибок или ошибок. Не используйте цикл для перебора массива, например for-of, for и т. д.

Используйте map() / every() / filter() / find() / findIndex() / reduce() / some() / … для перебора массивов и Object.keys() / Object.values() / Object.entries() для создания массивов, чтобы можно было перебирать объекты.

Документацию по вышеуказанным методам можно найти на mozilla.

Некоторые примеры:

const numbers = [1, 2, 3, 4, 5];

let sum = 0;
numbers.forEach((num) => {
  sum += num;
});
// sum = 15;

// Make use of the methods to improve code
const sum = numbers.reduce((total, num) => total + num, 0);
// sum = 15;

const increasedNumbers = numbers.map(num => num + 1);
// increasedNumbers = [2, 3, 4, 5, 6];

Обещания

ES6 предлагает встроенные обещания в JavaScript. Многие из вас знают об обетованиях и о том, почему они возникают.

Мы не будем углубляться в сами промисы, а продемонстрируем примеры промисов:

// A function that returns a promise after some time

// Without a promise constructor
function asyncExample(waitTime = 3000) {
	return setTimeout(() => Promise.resolve(), waitTime);
}

// With promise constructor
function asyncExample(waitTime = 3000) {
	// Prototype
	// <Promise>(resolve, reject)
	return new Promise((resolve) => setTimeout(resolve, waitTime));
}

asyncExample(5000).then(() => console.log('Will be logged after 5 secs.'));

Для обещаний есть чему поучиться, и, к счастью, у Mozilla действительно хорошая документация.