На этом занятии
рассмотрим работу операторов (- + * / % ++ --) в 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;
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");
Обратите
внимание на две последние операции. Здесь строки сначала приводятся к числовому
типу с помощью унарного +, а затем, выполняется сложение двух чисел.
Но, что если
записать сложение вот так:
Результатом
будет строка «52», а не «322». Почему? Потому что операторы выполняются слева
направо и сначала сложатся два числа 3+2=5, а затем, число 5 плюс строка «2»
получим строку «52».
Все следующие
операторы * / % ** ++ -- относятся к арифметическим и выполняют автоматическое
преобразование выражения к числу.
Операторы * и / выполняют
умножение и деление двух чисел, например,
let x="2", y = 5;
console.log(x/y); //0.4
Здесь строка «2»
автоматически была приведена к числу. И, если кто знаком с языком С++ и ему
подобными, обратите внимание, что при делении двух целых чисел результат
получается дробным, а не целым. Здесь все работает строго по математическим
правилам.
Умножение
работает аналогично:
Эти операторы
можно объединять и записывать, например, так:
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 );