Многих операторов мы знаем со школы. Это такие вещи, как сложение +
, умножение *
, вычитание -
и так далее.
В этой главе мы начнем с простых операторов, а затем сосредоточимся на аспектах, специфичных для JavaScript, не охваченных школьной арифметикой.
Прежде чем двигаться дальше, давайте разберемся с некоторой общей терминологией.
Операнд – это то, к чему применяются операторы. Например, при умножении 5 * 2
есть два операнда: левый операнд равен 5
, а правый операнд равен 2
. Иногда люди называют их «аргументами» вместо «операндов».
Оператор является унарным, если он имеет единственный операнд. Например, унарное отрицание -
меняет знак числа:
пусть х = 1; х = -х; оповещение (х); // -1, применено унарное отрицание
Оператор является бинарным , если он имеет два операнда. Тот же минус существует и в двоичной форме:
пусть х = 1, у = 3; оповещение ( у - х ); // 2, двоичный минус вычитает значения
Формально в приведенных выше примерах у нас есть два разных оператора, которые используют один и тот же символ: оператор отрицания, унарный оператор, меняющий знак, и оператор вычитания, бинарный оператор, который вычитает одно число из другого.
Поддерживаются следующие математические операции:
Дополнение +
,
Вычитание -
,
Умножение *
,
Разделение /
,
Остаток %
,
Возведение в степень **
.
Первые четыре просты, а о %
и **
нужно сказать несколько слов.
Оператор остатка %
, несмотря на свой внешний вид, не имеет отношения к процентам.
Результатом a % b
является остаток от целочисленного деления a
на b
.
Например:
предупреждение( 5 % 2 ); // 1, остаток 5 делим на 2 предупреждение( 8 % 3 ); // 2, остаток 8 делим на 3 предупреждение( 8 % 4 ); // 0, остаток от 8 разделить на 4
Оператор возведения в степень a ** b
возводит a
в степень b
.
В школьной математике мы пишем это как b .
Например:
предупреждение( 2 ** 2 ); // 2² = 4 предупреждение( 2 ** 3 ); // 2³ = 8 предупреждение( 2 ** 4 ); // 2⁴ = 16
Как и в математике, оператор возведения в степень определен и для нецелых чисел.
Например, квадратный корень — это возведение в степень в ½:
предупреждение( 4 ** (1/2) ); // 2 (степень 1/2 равна квадратному корню) предупреждение( 8 ** (1/3) ); // 2 (степень 1/3 равна кубическому корню)
Давайте познакомимся с особенностями операторов JavaScript, выходящим за рамки школьной арифметики.
Обычно оператор плюс +
суммирует числа.
Но если к строкам применяется двоичный +
, он объединяет (конкатенирует) их:
let s = «мой» + «строка»; оповещение(я); // загадочная строка
Обратите внимание: если какой-либо из операндов является строкой, то другой тоже преобразуется в строку.
Например:
предупреждение('1' + 2); // "12" предупреждение (2 + '1'); // "21"
Видите ли, не имеет значения, является ли первый операнд строкой или вторым.
Вот более сложный пример:
предупреждение (2 + 2 + '1'); // "41", а не "221"
Здесь операторы работают друг за другом. Первый +
суммирует два числа, поэтому возвращает 4
, затем следующий +
добавляет к нему строку 1
, так что это похоже на 4 + '1' = '41'
.
предупреждение('1' + 2 + 2); // "122", а не "14"
Здесь первый операнд — это строка, два других операнда компилятор тоже воспринимает как строки. 2
объединяется с '1'
, так что это похоже на '1' + 2 = "12"
и "12" + 2 = "122"
.
Бинарный +
— единственный оператор, поддерживающий строки таким образом. Другие арифметические операторы работают только с числами и всегда преобразуют свои операнды в числа.
Вот демо-версия вычитания и деления:
предупреждение (6 - '2'); // 4, преобразует '2' в число предупреждение('6'/'2'); // 3, преобразует оба операнда в числа
Плюс +
существует в двух формах: двоичной форме, которую мы использовали выше, и унарной форме.
Унарный плюс или, другими словами, оператор плюс +
примененный к одному значению, ничего не делает с числами. Но если операнд не является числом, унарный плюс преобразует его в число.
Например:
// Не влияет на числа пусть х = 1; предупреждение (+х); // 1 пусть у = -2; оповещение (+ у); // -2 // Преобразует не числа предупреждение (+истина); // 1 оповещение( +"" ); // 0
Фактически он делает то же самое, что и Number(...)
, но короче.
Необходимость преобразования строк в числа возникает очень часто. Например, если мы получаем значения из полей формы HTML, они обычно являются строками. Что, если мы хотим их суммировать?
Бинарный плюс добавит их как строки:
пусть яблоки = "2"; пусть апельсины = "3"; оповещение( яблоки + апельсины ); // "23", двоичный плюс объединяет строки
Если мы хотим рассматривать их как числа, нам нужно преобразовать, а затем суммировать их:
пусть яблоки = "2"; пусть апельсины = "3"; // оба значения преобразуются в числа перед двоичным плюсом alert( +яблоки + +апельсины ); // 5 // более длинный вариант // alert( Number(яблоки) + Number(апельсины) ); // 5
С точки зрения математика обилие плюсов может показаться странным. Но с точки зрения программиста здесь нет ничего особенного: сначала применяются унарные плюсы, они преобразуют строки в числа, а затем двоичный плюс их суммирует.
Почему унарные плюсы применяются к значениям раньше, чем двоичные? Как мы увидим, это связано с их более высоким приоритетом .
Если выражение имеет более одного оператора, порядок выполнения определяется их приоритетом или, другими словами, порядком приоритета операторов по умолчанию.
Все мы со школы знаем, что умножение в выражении 1 + 2 * 2
следует вычислять перед сложением. Это именно приоритет. Говорят, что умножение имеет более высокий приоритет, чем сложение.
Круглые скобки переопределяют любой приоритет, поэтому, если нас не устраивает порядок по умолчанию, мы можем использовать их, чтобы изменить его. Например, напишите (1 + 2) * 2
.
В JavaScript существует множество операторов. Каждый оператор имеет соответствующий номер приоритета. Первым выполняется тот, у кого номер больше. Если приоритет одинаковый, порядок выполнения — слева направо.
Вот выдержка из таблицы приоритетов (запоминать это не обязательно, но учтите, что унарные операторы стоят выше соответствующих бинарных):
Приоритет | Имя | Знак |
---|---|---|
… | … | … |
14 | унарный плюс | + |
14 | унарное отрицание | - |
13 | возведение в степень | ** |
12 | умножение | * |
12 | разделение | / |
11 | добавление | + |
11 | вычитание | - |
… | … | … |
2 | назначение | = |
… | … | … |
Как мы видим, «унарный плюс» имеет приоритет 14
, что выше, чем 11
«сложения» (двоичный плюс). Поэтому в выражении "+apples + +oranges"
перед сложением работают унарные плюсы.
Отметим, что присваивание =
также является оператором. Он указан в таблице приоритетов с очень низким приоритетом 2
.
Вот почему, когда мы присваиваем переменную, например x = 2 * 2 + 1
, сначала выполняются вычисления, а затем вычисляется =
, сохраняя результат в x
.
пусть х = 2*2+1; оповещение (х); // 5
Тот факт, что =
является оператором, а не «магической» языковой конструкцией, имеет интересное значение.
Все операторы в JavaScript возвращают значение. Это очевидно для +
и -
, но также верно и для =
.
Вызов x = value
записывает value
в x
и затем возвращает его .
Вот демонстрация, в которой присваивание используется как часть более сложного выражения:
пусть а = 1; пусть б = 2; пусть с = 3 – (а = b + 1); предупреждение(а); // 3 предупреждение(с); // 0
В приведенном выше примере результатом выражения (a = b + 1)
является значение, присвоенное a
(то есть 3
). Затем он используется для дальнейших оценок.
Забавный код, не правда ли? Нам следует понять, как это работает, потому что иногда мы видим это в библиотеках JavaScript.
Хотя, пожалуйста, не пишите такой код. Такие трюки определенно не делают код более понятным и читабельным.
Еще одна интересная функция — возможность связывать назначения:
пусть а, б, в; а = б = с = 2 + 2; предупреждение(а); // 4 предупреждение(б); // 4 предупреждение(с); // 4
Связанные назначения оцениваются справа налево. Сначала вычисляется самое правое выражение 2 + 2
, а затем присваивается переменным слева: c
, b
и a
. В конце концов, все переменные имеют одно значение.
Еще раз, для удобства чтения такой код лучше разбить на несколько строк:
в = 2 + 2; б = с; а = с;
Это легче читать, особенно при быстром сканировании кода глазами.
Нам часто необходимо применить оператор к переменной и сохранить новый результат в этой же переменной.
Например:
пусть n = 2; п = п + 5; п = п * 2;
Это обозначение можно сократить с помощью операторов +=
и *=
:
пусть n = 2; п += 5; // теперь n = 7 (то же самое, что n = n + 5) п *= 2; // теперь n = 14 (то же самое, что n = n * 2) предупреждение (н); // 14
Короткие операторы «изменения и присваивания» существуют для всех арифметических и побитовых операторов: /=
, -=
и т. д.
Такие операторы имеют тот же приоритет, что и обычное присваивание, поэтому они выполняются после большинства других вычислений:
пусть n = 2; п *= 3 + 5; // сначала вычисляется правая часть, так же, как n *= 8 предупреждение (н); // 16
Увеличение или уменьшение числа на единицу — одна из наиболее распространенных числовых операций.
Итак, для этого есть специальные операторы:
Increment ++
увеличивает переменную на 1:
пусть счетчик = 2; счетчик++; // работает так же, как counter = counter + 1, но короче предупреждение(счетчик); // 3
Декремент --
уменьшает переменную на 1:
пусть счетчик = 2; прилавок--; // работает так же, как counter = counter - 1, но короче предупреждение(счетчик); // 1
Важный:
Увеличение/уменьшение можно применять только к переменным. Попытка использовать его для значения типа 5++
приведет к ошибке.
Операторы ++
и --
можно размещать как до, так и после переменной.
Когда оператор идет после переменной, она находится в «постфиксной форме»: counter++
.
«Форма префикса» — это когда оператор идет перед переменной: ++counter
.
Оба эти утверждения делают одно и то же: увеличивают counter
на 1
.
Есть ли разница? Да, но мы сможем увидеть это, только если воспользуемся возвращаемым значением ++/--
.
Давайте уточним. Как мы знаем, все операторы возвращают значение. Увеличение/уменьшение не является исключением. Префиксная форма возвращает новое значение, а постфиксная форма возвращает старое значение (до увеличения/уменьшения).
Чтобы увидеть разницу, вот пример:
пусть счетчик = 1; пусть a = ++счетчик; // (*) предупреждение(а); // 2
В строке (*)
префикс формы ++counter
увеличивает counter
и возвращает новое значение 2
. Итак, alert
показывает 2
.
Теперь воспользуемся постфиксной формой:
пусть счетчик = 1; пусть а = счетчик++; // (*) заменил ++счетчик на счетчик++ предупреждение(а); // 1
В строке (*)
постфиксная форма counter++
также увеличивает counter
, но возвращает старое значение (до приращения). Итак, alert
показывает 1
.
Подводя итог:
Если результат увеличения/уменьшения не используется, нет разницы, в какой форме использовать:
пусть счетчик = 0; счетчик++; ++счетчик; предупреждение(счетчик); // 2, строки выше сделали то же самое
Если мы хотим увеличить значение и сразу использовать результат оператора, нам нужна форма префикса:
пусть счетчик = 0; оповещение(++счетчик); // 1
Если мы хотим увеличить значение, но использовать его предыдущее значение, нам нужна постфиксная форма:
пусть счетчик = 0; предупреждение(счетчик++); // 0
Увеличение/уменьшение среди других операторов
Операторы ++/--
также можно использовать внутри выражений. Их приоритет выше, чем у большинства других арифметических операций.
Например:
пусть счетчик = 1; предупреждение(2 *++счетчик); // 4
Сравните с:
пусть счетчик = 1; предупреждение( 2 * счетчик++ ); // 2, потому что counter++ возвращает "старое" значение
Хотя технически это нормально, такая нотация обычно делает код менее читабельным. Одна строка делает несколько вещей – это нехорошо.
При чтении кода быстрое «вертикальное» сканирование глаз может легко пропустить что-то вроде counter++
, и не будет очевидно, что переменная увеличилась.
Мы советуем стиль «одна линия – одно действие»:
пусть счетчик = 1; предупреждение (2 * счетчик); счетчик++;
Побитовые операторы рассматривают аргументы как 32-битные целые числа и работают на уровне их двоичного представления.
Эти операторы не зависят от JavaScript. Они поддерживаются большинством языков программирования.
Список операторов:
И ( &
)
ИЛИ ( |
)
Исключающее ИЛИ ( ^
)
НЕ ( ~
)
ЛЕВЫЙ СДВИГ ( <<
)
ПРАВЫЙ СДВИГ ( >>
)
ЗАПОЛНЕНИЕ НУЛЕМ ВПРАВО ( >>>
)
Эти операторы используются очень редко, когда нам нужно возиться с числами на самом низком (побитовом) уровне. Эти операторы нам не понадобятся в ближайшее время, поскольку в веб-разработке они мало используются, но в некоторых специальных областях, таких как криптография, они полезны. При необходимости вы можете прочитать главу «Побитовые операторы» на MDN.
Оператор запятая ,
один из самых редких и необычных операторов. Иногда он используется для написания более короткого кода, поэтому нам нужно его знать, чтобы понять, что происходит.
Оператор запятая позволяет нам вычислять несколько выражений, разделяя их запятой ,
. Каждый из них оценивается, но возвращается только результат последнего.
Например:
пусть а = (1+2, 3+4); предупреждение(а); // 7 (результат 3 + 4)
Здесь вычисляется первое выражение 1 + 2
и его результат отбрасывается. Затем вычисляется 3 + 4
и возвращается результат.
Запятая имеет очень низкий приоритет
Обратите внимание, что оператор запятая имеет очень низкий приоритет, ниже, чем =
, поэтому в приведенном выше примере важны круглые скобки.
Без них: a = 1 + 2, 3 + 4
сначала вычисляет +
, суммируя числа в a = 3, 7
, затем оператор присваивания =
присваивает a = 3
, а остальное игнорируется. Это как (a = 1 + 2), 3 + 4
.
Зачем нам оператор, который отбрасывает все, кроме последнего выражения?
Иногда люди используют его в более сложных конструкциях, чтобы поместить несколько действий в одну строку.
Например:
// три операции в одной строке for (a = 1, b = 3, c = a * b; a < 10; a++) { ... }
Подобные приемы используются во многих фреймворках JavaScript. Вот почему мы упоминаем их. Но обычно они не улучшают читаемость кода, поэтому нам следует хорошо подумать, прежде чем их использовать.
важность: 5
Каковы окончательные значения всех переменных a
, b
, c
и d
после кода ниже?
пусть а = 1, б = 1; пусть с = ++а; // ? пусть d = b++; // ?
Ответ:
a = 2
b = 2
c = 2
d = 1
пусть а = 1, б = 1; предупреждение( ++а ); // 2, форма префикса возвращает новое значение предупреждение(б++); // 1, постфиксная форма возвращает старое значение предупреждение(а); // 2, увеличивается один раз предупреждение(б); // 2, увеличивается один раз
важность: 3
Каковы значения a
и x
после кода ниже?
пусть а = 2; пусть х = 1 + (а *= 2);
Ответ:
a = 4
(умножается на 2)
x = 5
(рассчитывается как 1 + 4)
важность: 5
Каковы результаты этих выражений?
"" + 1 + 0 "" - 1+0 правда + ложь 6 / «3» «2» * «3» 4 + 5 + «пиксели» «$» + 4 + 5 «4» - 2 «4px» — 2 "-9" + 5 «-9» — 5 ноль + 1 не определено + 1 "tn" - 2
Хорошо подумайте, запишите и потом сравните с ответом.
"" + 1 + 0 = "10" // (1) "" - 1 + 0 = -1 // (2) истина + ложь = 1 6 / «3» = 2 «2» * «3» = 6 4 + 5 + «пикселей» = «9 пикселей» «$» + 4 + 5 = «45 долларов» «4» — 2 = 2 «4px» — 2 = НЭН "-9" + 5 = "-9 5" // (3) "-9" - 5 = -14 // (4) ноль + 1 = 1 // (5) неопределенное + 1 = НЭН // (6) "tn" - 2 = -2 // (7)
Сложение со строкой "" + 1
преобразует 1
в строку: "" + 1 = "1"
, и тогда у нас есть "1" + 0
, применяется то же правило.
Вычитание -
как и большинство математических операций) работает только с числами, оно преобразует пустую строку ""
в 0
.
Сложение со строкой добавляет к строке число 5
.
Вычитание всегда преобразуется в числа, поэтому " -9 "
становится числом -9
(игнорируя пробелы вокруг него).
null
становится 0
после числового преобразования.
undefined
становится NaN
после числового преобразования.
Пробелы обрезаются в начале и конце строки, когда строка преобразуется в число. Здесь вся строка состоит из пробелов, таких как t
, n
и «обычного» пробела между ними. Итак, как и пустая строка, она становится 0
.
важность: 5
Вот код, который запрашивает у пользователя два числа и показывает их сумму.
Это работает неправильно. Результат в приведенном ниже примере равен 12
(для значений подсказки по умолчанию).
Почему? Исправьте это. Результат должен быть 3
.
let a = Prompt("Первое число?", 1); let b = Prompt("Второе число?", 2); предупреждение (а + б); // 12
Причина в том, что приглашение возвращает пользовательский ввод в виде строки.
Таким образом, переменные имеют значения "1"
и "2"
соответственно.
пусть а = "1"; // Prompt("Первое число?", 1); пусть б = "2"; // Prompt("Второе число?", 2); предупреждение (а + б); // 12
Что нам нужно сделать, так это преобразовать строки в числа перед +
. Например, используя Number()
или добавляя к ним +
.
Например, прямо перед prompt
:
let a = +prompt("Первое число?", 1); let b = +prompt("Второе число?", 2); предупреждение (а + б); // 3
Или в alert
:
let a = Prompt("Первое число?", 1); let b = Prompt("Второе число?", 2); оповещение(+а + +б); // 3
Использование как унарного, так и двоичного +
в последней версии кода. Выглядит забавно, не так ли?