Розуміння ECMAScript 7 (2016)

Розробка ECMAScript 6 зайняла близько чотирьох років, і пілся цього, TC-39 вирішив, що такий довгий процес розробки є неприйнятним. Замість цього, вони перейшли до щорічного релізного циклу, щоб забезпечити швидше надходження нововведень мови у розробку.

Більш часті релізи означають, що кожна нова редакція ECMAScript матиме меншу кількість нововведень ніж ECMAScript 6. Щоб підкреслити цю зміну, нові версії специфікації більше не акцентують увагу на номері редакції. Замість цього нові версії посилаються на рік публікації специфікації. В результаті, ECMAScript 6 також відомий як ECMAScript 2015, а ECMAScript 7 формально відомий як ECMAScript 2016. TC-39 збирається використовувати систему іменування прив’язану до року публікації для майбутніх редакцій ECMAScript.

ECMAScript 2016 був завершений у березні 2016 і містить лише три розширення мови: математичний оператор, новий метод масивів та нову синтаксичну помилку. Про них ітиметься у цьому додатку.

Експоненціальний оператор

Єдиною зміною у синтаксисі JavaScript, яка вводиться ECMAScript 2016, є експоненціальний оператор (exponentiation operator), який є математичною операцію піднесення до степеня. JavaScript також мав метод Math.pow() для виконання цієї операції, проте JavaScript був однією з небагатьох мов, які вимагали для цього метод, а не формальний оператор. (І деякі розробники вважають оператор простішим для читання та розуміння.)

Експоненціальним оператором є дві зірочки (**), де лівий операнд є основою, а правий — степенем. Наприклад:

let result = 5 ** 2;

console.log(result);                        // 25
console.log(result === Math.pow(5, 2));     // true

Цей приклад обчислює 5^2^, що дорівнює 25. Ви також можете використовувати Math.pow() для отримання такого ж результату.

Порядок операцій

Експоненціальний оператор має найвищий пріоритет з усіх бінарних операторів у JavaScript (унарні оператори мають вищий пріоритет ніж **). Це означає, що він застосовується першим у складених операціях, як у цьому прикладі:

let result = 2 * 5 ** 2;
console.log(result);        // 50

Спершу обчислюється 5^2^. Отриманий результат множиться на 2 і отримується остаточний результат 50.

Обмеження операндів

Експоненціальний оператор має одне незвичайне обмеження, якого немає у інших операторів. Лівою частиною експоненціальної операції не може бути будь–який унарний вираз, окрім ++ або --. Наприклад, такий синтаксис не є валідним:

// синтаксична помилка
let result = -5 ** 2;

У цьому прикладі -5 є синтаксичною помилкою, бо порядок операцій є неоднозначним. Чи має - застосовуватись до 5, чи до результату виразу 5 ** 2? Заборона використання унарних виразів у лівій частині експоненціального оператора виключає цю невизначеність. Для того, щоб чітко визначити порядок вам потрібно додати круглі дужки довкола -5 або довкола 5 ** 2, ось так:

// добре
let result1 = -(5 ** 2);    // дорівнює -25

// також добре
let result2 = (-5) ** 2;    // дорівнює 25

Якщо ви додасте круглі дужки довкола виразу, - застосується до результату. Коли ж ви обернете у круглі дужки -5, буде точно зрозуміло, що ви хочете піднести -5 до квадрату.

Вам не потрібні круглі дужки при використанні ++ та -- у лівій частині експоненціального оператора, тому що оператори мають чітко визначену поведінку над своїми операндами. Префікс ++ або -- змінюють операнд до того, як застосується будь–яка інша операція, постфіксні версії не виконають жодних змін, доки весь вираз не буде обчислено. Обидва випадки є безпечними у лівій частині цього оператора, і приклад це демонструє:

let num1 = 2,
    num2 = 2;

console.log(++num1 ** 2);       // 9
console.log(num1);              // 3

console.log(num2-- ** 2);       // 4
console.log(num2);              // 1

У цьому прикладі, num1 збільшується до того, як застосовується експоненціальний оператор, тому num1 стає 3, а результатом операції є 9. Для num2, значення залишається 2 для експоненціального оператора, а потім результат зменшується на 1.

Метод Array.prototype.includes()

Ви маєте пам’ятати, що ECMAScript 6 додав String.prototype.includes() для перевірки того, чи підрядок є частиною даного рядка. Початково, ECMAScript 6 також мав додати метод Array.prototype.includes(), щоб продовжити тенденцію до трактування рядків та масивів однаковим чином. Проте специфікація для Array.prototype.includes() не була завершеною вчасно, і тому Array.prototype.includes() з’являється лише в ECMAScript 2016.

Як використовувати Array.prototype.includes()

Метод Array.prototype.includes() приймає два аргументи: значення для пошуку і необов’язковий індекс з якого потрібно починати пошук. Якщо передати другий аргумент, includes() почне шукати співпадіння починаючи з вказаного індекса. (За замовчуванням початковим індексом є 0.) Результатом є true, якщо значення знайдено всередині масиву, і false, якщо ні. Наприклад:

let values = [1, 2, 3];

console.log(values.includes(1));        // true
console.log(values.includes(0));        // false

// шукаємо, починаючи з індексу 2
console.log(values.includes(1, 2));     // false

Тут виклик values.includes() повертає true для значення 1 та false для значення 0, тому що 0 немає у масиві. Коли використовується другий аргумент, щоб починати пошук з індексу 2 (який містить значення 3), метод values.includes() повертає false, тому що число 1 не знайдено поміж індексом 2 та кінцем масиву.

Порівняння значень

Порівняння значень, яке відбувається у методі includes(), використовує оператор === з одним виключенням: NaN вважається рівним NaN, не дивлячись на те, що NaN === NaN обчислюється у false. Ця відрізняється від поведінки методу indexOf(), який для порівняння строго використовує ===. Щоб побачити відмінність, розгляньте код:

let values = [1, NaN, 2];

console.log(values.indexOf(NaN));       // -1
console.log(values.includes(NaN));      // true

Метод values.indexOf() повертає -1 для NaN, незважаючи на те, що NaN міститься у масиві values. З іншого боку, values.includes() повертає true для NaN, тому що він використовує інший оператор порівняння.

W> Коли ви хочете перевірити існування значення у масиві і вам не потрібно дізнаватись його індекс, я раджу використовувати includes(), через відмінність того, як NaN трактується у методах includes() та indexOf(). Якщо ж вам потрібно дізнатись де значення існує у масиві, тоді ви маєте використовувати метод indexOf().

Іншою підступністю цієї імплементації є те, що +0 та -0 вважаються однаковими. У цьому випадку, поведінка indexOf() та includes() є однаковою:

let values = [1, +0, 2];

console.log(values.indexOf(-0));        // 1
console.log(values.includes(-0));       // true

Тут, і метод indexOf(), і метод includes() знаходять +0, коли передається -0, тому що обидва значення вважаються однаковими. Зауважте, що це відрізняється від поведінки метода Object.is(), який вважає +0 та -0 різними значеннями.

Зміни у строгому режимі функціональної області видимості

Коли ECMAScript 5 ввів строгий режим, мова була дещо простішою ніж вона стала у ECMAScript 6. Незважаючи на це, ECMAScript 6 дозволяв використовувати строгий режим через використання директиви "use strict" у глобальній області видимості (що запустило б весь код у строгому режимі) або у функціональній області видимості (так, щоб лише функція запускалась у строгому режимі). Останній спосіб був проблематичним у ECMAScript 6 через більш складні способи визначення параметрів, наприклад, з деструктуруванням, значеннями параметрів за замовчуванням. Щоб зрозуміти проблему, розгляньте такий код:

function doSomething(first = this) {
    "use strict";

    return first;
}

Тут іменованому параметру first присвоюється значення за замовчуванням this. Яке значення матиме first? Специфікація ECMAScript 6 вказує рушієві JavaScript трактувати параметри, у цьому випадку так, як під час запуску у строгому режимі, тому this має бути рівним undefined. Однак, імплементація параметрів, які запускаються у строгому режимі, коли всередині функції присутня директива "use strict", стає складною через те, що значенням за замовчуванням також може бути функція. Ця складність призвела до того, що більшість рушіїв JavaScript не імплементують це нововведення (тому this був би рівним глобальному об’єкту).

Внаслідок складнощів, пов’язаних з імплементацією, ECMAScript 2016 забороняє мати директиву "use strict" всередині функції, параметри якої містять деструктурування або значення за замовчуванням. Лише простий список параметрів, який не містить декструктурування або значень за замовчуванням, дозволений коли тіло функції містить "use strict". Ось кілька прикладів:

// добре - використання простого списку параметрів
function okay(first, second) {
    "use strict";

    return first;
}

// синтаксична помилка
function notOkay1(first, second=first) {
    "use strict";

    return first;
}

// синтаксична помилка
function notOkay2({ first, second }) {
    "use strict";

    return first;
}

Ви досі можете використовувати "use strict" з простим списком параметрів, ось чому okay() працює так, як і очікується (так само, як би він працював у ECMAScript 5). Функція notOkay1() має синтаксичну помилку, тому що ви не можете використовувати "use strict" у функціях зі значеннями параметрів за замовчуванням. Так само, функція notOkay2() має синтаксичну помилку, бо ви не можете використовувати "use strict" у функції з деструктивним параметром.

Зрештою, ця зміна звільняє як і JavaScript–розробників від плутанини, так і рушії JavaScript від проблеми з імплементацією.

results matching ""

    No results matching ""