The Exponentiation Operator

Единствената промяна в 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.

Operand Restriction

Оператора за степенуване има малко необичайно ограничение, което не присъства в другите оператори. Лявата страна на операцията за степенуване, не може да бъде унарен израз, освен ++ или --. Например това е невалиден синтаксис:

// syntax error
let result = -5 ** 2;
	 			

В този пример -5 е синтактична грешка, защото редът на операциите е двусмислен. Не се разбира дали - се прилага само за 5 или за резултата на израза 5 ** 2. Забраната на унарни изрази от лявата страна на оператора за степенуване елиминира тази неяснота. За да се посочи ясно намерение, трябва да се включат скоби, около -5 или около 5 ** 2, както следва:

// ok
let result1 = -(5 ** 2);    // equal to -25

// also ok
let result2 = (-5) ** 2;    // equal to 25
	 			

Ако поставите скобите около израза, - се прилага към цялата работа. Когато скобите заобикалят -5, става ясно, че искате да повдигнете -5 на втората степен.

Няма нужда от скоби, ако се използва ++ и -- от лявата страна на оператора за степенуване, защото двата оператора имат ясно дефинирано поведение на техните операнти. Префикс ++ или -- променя операнта преди да се извършат всички други операции и версии на postfix прилагат някакви промени едва след оценка на целия израз. Случаи на използване на двата са безопасни от лявата страна на оператора, като този код показва:

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(), който проверява дали някои определени substrings съществуват в рамките на даден string. Първоначално ECMAScript 6 също искаше да въведе Array.prototype.includes() метод, за да продължи тенденцията на третиране на strings и arrays по същия начин. Но спецификацията за Array.prototype.includes() не беше пълна в крайния срок за ECMAScript 6 и така Array.prototype.includes() се озова в ECMAScript 2016.

Как да използваме Array.prototype.includes()

Методът Array.prototype.includes() приема два аргумента: стойността за търсене и незадължителен индекс, от който да започне търсенето. Когато e подаден втория аргумент, includes() започва съвпадението от този индекс. (По подразбиране началния индекс е 0.) Върнатата стойност е true, ако стойността се намира вътре в array и false ако не е. Например:

let values = [1, 2, 3];

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

// start the search from index 2
console.log(values.includes(1, 2));     // false
	 			

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

Сравняване на стойност

Сравняването на стойност, извършвано от метода 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 се съдържа в array. От друга страна values.includes() връща true за NaN, защото използва различна стойност за оператора за сравнение.

worning
Когато искате да проверите за съществуването на само една стойност в array, не е необходимо да се знае индекса, аз препоръчвам да използвате includes() поради разликата в това как се третира NaN от includes() и indexOf() методите. Ако трябва да знаете къде съществува дадена стойност в array, тогава трябва да използвате метода 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 за различни стойности.

Промяна на обхвата на функцията в Strict Mode

Когато strict mode беше въведен в ECMAScript 5, езикът стана съвсем малко по-лесен, отколкото в ECMAScript 6. Въпреки това, във ECMAScript 6 все още е разрешено да укажете стриктен режим с помощта на "use strict" директивата или в глобалния обхват на действие (което ще направи целия код в strict mode) или в обхвата на функция (така само функцията ще работи в strict mode). Последното се оказа проблем в ECMAScript 6 поради по-сложния начин, по който параметрите може да се определят, по-конкретно, с преструктуриране и default стойности за параметър. За да разберем проблема, да разгледаме следния код:

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

    return first;
}
	 			

Тука, към името на параметъра first се присвоява стойност по подразбиране this. Каква стойност очаквате да бъде first? Спецификацията на ECMAScript 6 инструктира JavaScript машината в такива случаи да третира параметрите, като че работят в стриктен режим, така че this трябва да бъде равен на undefined. Въпреки това, изпълнението на параметри работещи в стриктен режим, когато "use strict" присъства вътре във функцията, се оказа доста трудно, защото стойностите за параметър по подразбиране могат да бъдат и функции. Тази трудност доведе до повечето JavaScript машини да не изпълняват такива функции (така this ще бъде равен на глобалния обект).

В резултат от трудността на изпълнение ECMAScript 2016, направи незаконно да има "use strict" директива вътре във функция, чиито параметри са destructured или имат default стойности. Разрешени са само прости списъци с параметри, тези които не съдържат destructured или стойности по подразбиране, когато "use strict" присъства в тялото на функция. Ето някои примери:

// okay - using simple parameter list
function okay(first, second) {
    "use strict";

    return first;
}

// syntax error
function notOkay1(first, second=first) {
    "use strict";

    return first;
}

// syntax error
function notOkay2({ first, second }) {
    "use strict";

    return first;
}
	 			

Все още можете да използвате "use strict" с прости списъци от параметри, поради което okay() работи, както бихте очаквали (също, както в ECMAScript 5). Функцията notOkay1() е синтактична грешка, защото вече не може да използвате "use strict" във функции с default стойности на параметрите. По същия начин notOkay2() функцията е синтактична грешка, защото не можете да използвате "use strict" във функция с destructured параметри.

Като цяло, тази промяна премахва една точка от объркване на JavaScript програмистите, както и проблемното изпълнение за JavaScript машините.