Клавиша / esc

Базовые операторы в JS

Обзор ключевых операторов JavaScript: арифметика, приоритет, инкремент и декремент, присваивание.

Время чтения: 7 мин

Кратко

Скопировано

В 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 попытается привести их к примитиву через метод toString() или valueOf(). Иногда это приводит к результатам, которые сложно предсказать, если не знать механизма преобразований:

        
          
          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, вернётся 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.

Зачем это нужно?

  1. Короткая запись. Вместо x = x + 10 можно использовать x += 10;
  2. Удобство при изменении счётчика. В циклах или при пошаговом изменении переменной такие записи упрощают код и делают его немного выразительнее.

Инкремент и декремент

Скопировано

Инкремент и декремент — это унарные операторы, которые увеличивают или уменьшают значение переменной на 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, --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 связаны с особенностями постфиксной или префиксной формы. Если не помните, когда возвращается старое значение, а когда новое, лучше используйте отдельные инструкции присваивания.