Кратко
СкопированоВ JavaScript есть несколько базовых операторов, с которыми разработчики сталкиваются постоянно в ходе своей работы. Они позволяют выполнять арифметические действия, изменять значения переменных, а также помогают разработчику упростить некоторые операции в коде.
Кто такие: «оператор», «операнд»?
Скопировано-
Оператор — символ (или ключевое слово), говорящий движку, какую операцию совершить
-
Операнд — это то, над чем оператор выполняет действие (например: число, строка, переменная)
Типы операторов
СкопированоУнарные операторы
СкопированоУнарные операторы зависят от одного операнда. Другими словами, они действуют только на один объект.
Пример — унарный минус -
:
let x = 5console.log(-x)// -5
let x = 5 console.log(-x) // -5
Бинарные операторы
СкопированоБинарные операторы применяются к двум операндам.
Например, оператор +
применяется к операндам x
и y
:
const x = 5, y = 2console.log(x + y)// 7
const x = 5, y = 2 console.log(x + y) // 7
Рассмотрим другой пример: оператор >
сравнивает числа и возвращает значение логического типа:
const user = { age: 19 }console.log(user.age > 18)// true
const user = { age: 19 } console.log(user.age > 18) // true
Математика
СкопированоJavaScript поддерживает стандартные арифметические операторы, которые помогают складывать, вычитать, умножать и делить числа. Ниже перечислены самые популярные из них:
Сложение, вычитание, умножение и деление
Скопированоconsole.log(10 + 3)// 13console.log(10 - 3)// 7console.log(10 * 3)// 30console.log(10 / 3)// 3.3333...console.log(10 - 'blablabla')// NaN
console.log(10 + 3) // 13 console.log(10 - 3) // 7 console.log(10 * 3) // 30 console.log(10 / 3) // 3.3333... console.log(10 - 'blablabla') // NaN
Остаток от деления
Скопированоconsole.log(10 % 3)// 1console.log(8 % 2)// 0
console.log(10 % 3) // 1 console.log(8 % 2) // 0
Возведение в степень
Скопированоconsole.log(2 ** 2)// 4console.log(2 ** 5)// 32
console.log(2 ** 2) // 4 console.log(2 ** 5) // 32
Не только математика
СкопированоJavaScript позволяет применять операторы не только к числам — на практике можно встретить ситуации, когда один или оба операнда оказываются строками, булевыми значениями или даже объектами.
Как выполнение операторов описывает спецификация ECMAScript
Рассмотрим шаги, определённые в спецификации ECMAScript на примере оператора +
:
Сначала оба операнда последовательно приводятся к примитивам. Если хотя бы один из операндов — строка, то второй операнд будет приведён к строке и результатом операции будет конкатенация:
console.log(5 + '2')// '52'
console.log(5 + '2') // '52'
В противном случае операция рассматривается как арифметическая. JavaScript приводит оба операнда к числовому типу — Number или BigInt. Если один операнд оказался Number, а другой — BigInt, будет выброшена ошибка TypeError:
42n + 1 // TypeError: Cannot mix BigInt and other types, use explicit conversions
42n + 1 // TypeError: Cannot mix BigInt and other types, use explicit conversions
Если оба операнда — Number, используется операция Number::add. Если оба операнда оказываются BigInt, вызывается BigInt:add:
console.log(2 + 3)// 5console.log(2n + 3n)// 5n
console.log(2 + 3) // 5 console.log(2n + 3n) // 5n
Конкатенация строк
СкопированоЕсли хотя бы один операнд у оператора +
— строка, в результате получится склейка (конкатенация). Например:
console.log('Hello' + ' ' + 'world')// 'Hello world'console.log('5' + 2)// '52'
console.log('Hello' + ' ' + 'world') // 'Hello world' console.log('5' + 2) // '52'
Сравнение строк
СкопированоОператоры сравнения, такие как >
или <
, могут применяться к строкам. При этом строки сравниваются лексикографически — посимвольно в порядке символов, а не по их «числовому» содержанию.
Следующее выражение возвращает true
после сравнения первых символов строк '2'
и '15'
— '2'
и '1'
:
console.log('2' > '15')// true
console.log('2' > '15') // true
Каждому символу соответствует код из UTF-16, с помощью которого и происходит сравнение двух символов.
Преобразование нечисловых типов
СкопированоВо время выполнения арифметических операций JavaScript пытается преобразовать операнды к числу. Например, при использовании оператора -
со строкой:
let x = '10'console.log(x - 1)// 9, строка '10' привелась к числу 10
let x = '10' console.log(x - 1) // 9, строка '10' привелась к числу 10
Также существует унарный плюс +
, который явно превращает строку в число:
console.log(+'42')// 42
console.log(+'42') // 42
При попытке использовать арифметические операторы вроде +
, -
или *
с объектами или массивами, JavaScript попытается привести их к примитиву через метод to
или value
. Иногда это приводит к результатам, которые сложно предсказать, если не знать механизма преобразований:
console.log({} + {})// '[object Object][object Object]'// В массиве по умолчанию toString() склеивает элементы:console.log([1, 2, 3] + [4, 5])// '1,2,34,5'
console.log({} + {}) // '[object Object][object Object]' // В массиве по умолчанию toString() склеивает элементы: console.log([1, 2, 3] + [4, 5]) // '1,2,34,5'
В арифметическом контексте true
приводится к 1
, а false
— к 0
. Однако при конкатенации строк (+
) булевые значения не будут автоматически превращаться в числа:
console.log(true + 1)// 2console.log(false + 10)// 10console.log(true + '1')// 'true1'
console.log(true + 1) // 2 console.log(false + 10) // 10 console.log(true + '1') // 'true1'
Подробнее о том, как JavaScript преобразует строки, объекты и другие типы данных, можно посмотреть в статье преобразование типов.
Приоритет операторов
СкопированоВ JavaScript у операторов есть определённый порядок выполнения. Это означает, что некоторые операции будут выполняться раньше других, если в выражении нет дополнительных скобок.
Приоритет унарных операторов выше, чем приоритет бинарных (за некоторыми исключениями: оператор группировки, вызов функции, доступ к свойствам и т. п.). Подробнее можно посмотреть в таблице приоритетов.
На практике запоминать приоритет всех операторов не нужно: в спорных случаях всегда лучше проставить скобки явно.
Присваивание
СкопированоОператор присваивания =
в JavaScript находится почти в самом низу приоритетов. Его суть проста: взять значение выражения справа и присвоить переменной слева. Например:
const result = 10
const result = 10
Важно, что оператор присваивания возвращает значение, которое было присвоено переменной:
let aconsole.log(a = 'Hello world!')// 'Hello world!'
let a console.log(a = 'Hello world!') // 'Hello world!'
Оператор присваивания выполняется справа налево. В примере ниже, сначала выполнится b
, вернётся 5
, а затем значение присвоится a
. В итоге a
и b
оба станут равны 5
:
let a, bconsole.log(a = b = 5)// 5console.log(a, b)// 5 5
let a, b console.log(a = b = 5) // 5 console.log(a, b) // 5 5
Как делать не надо
СкопированоИногда можно увидеть слишком хитрые конструкции, где в одном выражении смешиваются разные операторы, в том числе присваивания. Например:
const a = 2 + (b = 3 * 5) // a = 17, b = 15
const a = 2 + (b = 3 * 5) // a = 17, b = 15
Такой код работает, но его сложно читать и поддерживать, особенно если в нём участвуют более сложные вычисления. В большинстве случаев лучше разбить логику на несколько строк — так понятнее и надёжнее:
const b = 3 * 5 // 15const a = 2 + b // 17
const b = 3 * 5 // 15 const a = 2 + b // 17
Инкрементное присваивание
СкопированоПомимо обычного оператора =
, в JavaScript есть целая группа сокращённых операторов присваивания. Они позволяют одновременно выполнить арифметическую операцию и присвоить результат переменной. Например:
x +
эквивалентно= 1 x
;= x + 1 x
эквивалентно- = 2 x
;= x - 2 x *
эквивалентно= 3 x
;= x* 3 x
эквивалентно/ = 4 x
;= x / 4 x
эквивалентно% = 5 x
;= x % 5 x **
эквивалентно= 6 x
.= x ** 6
Зачем это нужно?
- Короткая запись. Вместо
x
можно использовать= x + 10 x +
;= 10 - Удобство при изменении счётчика. В циклах или при пошаговом изменении переменной такие записи упрощают код и делают его немного выразительнее.
Инкремент и декремент
СкопированоИнкремент и декремент — это унарные операторы, которые увеличивают или уменьшают значение переменной на 1
. Выглядят они так:
- Инкремент:
++
, - Декремент:
-
.-
При этом существует две формы — префиксная и постфиксная. Они отличаются моментом, когда переменная меняет своё значение.
Постфиксная форма
СкопированоПостфиксные операторы (x++
, x
) сначала возвращают старое значение, а лишь затем меняют переменную:
let x = 5console.log(x++)// 5 (возвращаем старое значение)console.log(x)// 6 (теперь переменная увеличена)
let x = 5 console.log(x++) // 5 (возвращаем старое значение) console.log(x) // 6 (теперь переменная увеличена)
Префиксная форма
СкопированоПрефиксные операторы (++x
, -
) сначала изменяют переменную, а затем возвращают новое значение:
let count = 5console.log(++count)// 6 (значение уже увеличено)console.log(count)// 6 (значение остаётся увеличенным)
let count = 5 console.log(++count) // 6 (значение уже увеличено) console.log(count) // 6 (значение остаётся увеличенным)
Когда использовать
СкопированоИнкремент и декремент нередко применяют в циклах for
или while
, чтобы удобнее управлять переменными-счётчиками. Вывод чисел от 0 до 4 (включительно) в консоль может выглядеть так:
for (let i = 0; i < 5; i++) { console.log(i)}
for (let i = 0; i < 5; i++) { console.log(i) }
Подводные камни
СкопированоЧаще всего проблемы в использовании инкремента или декремента в JavaScript связаны с особенностями постфиксной или префиксной формы. Если не помните, когда возвращается старое значение, а когда новое, лучше используйте отдельные инструкции присваивания.