Арифметические операции

На этом занятии рассмотрим работу операторов (- + * / % ++ --) в JavaScript. Но вначале немного терминологии, чтобы мы понимали друг друга:

Операнд – то, к чему применяется оператор.

Например, в умножении 5 * 2 есть два операнда: левый операнд равен 5, а правый операнд равен 2. Иногда их называют «аргументами» вместо «операндов».

Унарным называется оператор, который применяется к одному операнду.

Например, оператор унарный минус "-" меняет знак числа на противоположный:

let a = 1;
a=-a;   //унарный минус

Бинарным называется оператор, который применяется к двум операндам.

Тот же минус существует и в бинарной форме:

let a = 1, b = 2;
b-a;    //бинарный минус

Из этих примеров видно, что унарный минус и бинарный минус – это два совершенно разных оператора: в первом случае он меняет знак, а во втором – реализует вычитание.

Раз мы заговорили об операторе -, начнем с него. Итак, унарный минус и вычитание для чисел работает очевидным образом по математическим правилам:

let x = 2.8, y = 7.3;
console.log(x-y);

Но, что если один из операндов не будет числом, например, строкой:

let x = "2.8", y = 7.3;

В этом случае он сначала приводится к числу, а затем, применяется данный оператор:

let x = "2.8", y = 7.3;
console.log(x-y);

И в этом случае:

let arg = -x;
console.log(typeof arg);

Как видите, тип переменной стал number. Если вместо строки взять любой другой тип, то он также будет приводиться к number:

let x = true, y = null, z = undefined;
console.log(-x);    // -1
console.log(-y);    // -0
console.log(-z);     //NaN
console.log(typeof -x, typeof -y, typeof -z);

Следующий оператор + работает несколько иначе. Для чисел все то же самое:

let x = 4, y = 7;
let sum = x+y;
console.log(sum);

Унарный плюс тоже все пытается перевести в числа, если это возможно:

let x = "4", y = "не число", z = true, t = null, u = undefined;
console.log(typeof +x, typeof +y, typeof +z, typeof +t);
console.log(+x, +y, +z, +t, +u);

Все будет приведено к числовому типу с результатом:

4 NaN 1 0 NaN

Здесь строка «не число» и значение undefined преобразовались в NaN, остальные величины в соответствующие числа.

Учитывая, что унарный + не искажает чисел, его часто используют для преобразования выражения к числовому типу вместо Number, то есть:

+"46"  написать гораздо быстрее, чем Number("46")

А вот при сложении двух операндов + работает не только как арифметическая операция. С его помощью можно делать соединение двух строк (или как еще говорят: конкатенацию строк). Например,

let str1 = "Hello", str2 = "Wordl!";
console.log(str1+str2);

Получим строку «HelloWorld!». Добавим пробел между словами:

console.log(str1+" "+str2);

получим «Hello World!». То есть, бинарный оператор либо объединяет строки, либо складывает два числа. Но как понять: когда он будет складывать, а когда объединять? Например, вот в таких вариантах:

console.log(5+"6");
console.log("6"+10);
console.log("6.46"+10);
console.log(-2+"1.3");

Здесь везде будет происходить соединение двух строк. Почему так? Правило очень простое. Если один из операндов бинарного оператора + является строкой, то оба операнда преобразуются в строки и объединяются в единую строку. Если же оба операнда – числа, то выполняется их математическое сложение. Например, вот здесь везде значения будут складываться как числа:

console.log(5+2);
console.log(true+10);
console.log(null+10);
console.log(-2 + +"1.3");
console.log(+"6" + +"3");

Обратите внимание на две последние операции. Здесь строки сначала приводятся к числовому типу с помощью унарного +, а затем, выполняется сложение двух чисел.

Но, что если записать сложение вот так:

console.log(3+2+"2");

Результатом будет строка «52», а не «322». Почему? Потому что операторы выполняются слева направо и сначала сложатся два числа 3+2=5, а затем, число 5 плюс строка «2» получим строку «52».

Все следующие операторы * / % ** ++ -- относятся к арифметическим и выполняют автоматическое преобразование выражения к числу.

Операторы * и / выполняют умножение и деление двух чисел, например,

let x="2", y = 5;
console.log(x/y);   //0.4

Здесь строка «2» автоматически была приведена к числу. И, если кто знаком с языком С++ и ему подобными, обратите внимание, что при делении двух целых чисел результат получается дробным, а не целым. Здесь все работает строго по математическим правилам.

Умножение работает аналогично:

console.log(x*y);

Эти операторы можно объединять и записывать, например, так:

console.log(x*y+1.3/6-10);

Соответственно порядок их выполнения определяется приоритетами. Как и в математике приоритет у операций * и / выше, чем у + и -, поэтому сначала делается умножение и деление, а затем, сложение и вычитание. Если нужно изменить приоритеты, то также как и в математике, используются круглые скобки:

console.log(x*(y+1.3)/6-10);

Здесь сначала делается сложение в скобках, а затем, все остальные операции в порядке их приоритетов.

Следующая операция % вычисляет остаток от деления одного числа на другое, например,

console.log( 5 % 2 ); // 1, остаток от деления 5 на 2
console.log( 8 % 3 ); // 2, остаток от деления 8 на 3
console.log( 6 % 3 ); // 0, остаток от деления 6 на 3

Причем, в отличие от многих других языков программирования, здесь можно записывать и вещественные числа:

console.log( 5.2 % 2.3 ); // примерно 0.6

Но все-таки ее обычно применяют именно к двум целым числам.

Следующая операция ** возведение в степень. Например:

console.log( 2 ** 2 ); // 4  (2 * 2)
console.log( 2 ** 3 ); // 8  (2 * 2 * 2)
console.log( 4 ** 2 ); // 16  (4 * 4)

Она также может работать и с дробными значениями:

console.log( 4 ** (1/2) ); // 2 (степень 1/2 эквивалентна взятию квадратного корня)
console.log( 8 ** (1/3) ); // 2 (степень 1/3 эквивалентна взятию кубического корня)

Последние две операции ++ (инкремент) и -- (декремент) увеличивают и уменьшают значение переменной на 1:

let counter = 2, cnt = 5;
counter++; // работает как counter = counter + 1 
cnt--; // работает как cnt = cnt - 1 
console.log( counter, cnt ); // 3, 4

Операции ++ и -- не только записываются короче, но и быстрее исполняются JavaScript-машиной, чем аналогичные операции

counter = counter + 1  и cnt = cnt - 1

Причем, считается, что для увеличения производительности предпочтительнее использовать префиксную запись:

++counter и --cnt

Но эти две операции (префиксная и постпрефиксная) отличаются не только скоростью исполнения. У них есть другой нюанс. Покажем его на таком примере:

let a, b, c = 10, d = 10;
a = c++;
b = ++d;
console.log( a, b, c, d );

Получим результат: a=10, b=11, c=11, d=11. Обратите внимание, что значение переменной a равно 10, а не 11. Это из-за того, что при постпрефиксной записи сначала выполняется присваивание значение a=c и только потом переменная c увеличивается на 1. При префиксной записи, сначала значение переменной d увеличивается на 1, а затем, число 11 присваивается переменной b. Отсюда и получаются такие результаты. Вот это нужно запомнить и иметь в виду при написании скриптов.

Приоритет у операций ++ и -- выше, чем у операций * и /, поэтому они корректно будут работать при такой записи:

let a = 4;
console.log(2 * ++a);

В программировании часто приходится менять значение переменной на определенную величину. Например, увеличить на 5, или уменьшить на 2, или увеличить в 10 раз, уменьшить в 4 раза и так далее. Все это можно выполнить такими короткими операторами:

let a = 0, b = 1;
a += 5;        // эквивалент: a = a + 5
b -= 2;        // эквивалент: b = b - 2
console.log( a, b );
a *= 10; // эквивалент: a = a * 10
b /= 4;          // эквивалент: b = b / 4
console.log( a, b );

Видео по теме