Сначала рассмотрим уже знакомые вам операции: сложение (+), вычитание (-), умножение (*) и деление (/). Это все операторы, которые можно применять к числам с любым основанием, поэтому не имеет значения, воспринимаем ли мы числа как двоичные или с основанием 10.

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

Прежде чем мы перейдем к тому, почему они полезны, давайте рассмотрим ключевые из них и объясним, как они работают и выглядят.

Не оператор(~)

Поскольку оператор является унарным, он принимает только один операнд. Оператор применяет операцию НЕ к каждому биту своего операнда. Дополнение является результатом операции НЕ. Дополнение к целому числу генерируется инвертированием каждого бита целого числа.

// 170 => 00000000000000000000000010101010
// --------------------------------------
//  ~ 00000000000000000000000010101010
// --------------------------------------
//  = 11111111111111111111111101010101
// --------------------------------------
//  = -171 (decimal)

console.log(~170); // -171

Побитовое И (&)

Оператор & выполняет операцию И над каждой парой совпадающих битов операндов. Если оба бита равны 1, оператор & возвращает 1; в противном случае возвращается 0. В результате результат операции И будет таким же, как умножение каждой пары связанных битов.

Вот различные значения операции И для пары битов.

(0 & 0) === 0     // 0 x 0 = 0
(0 & 1) === 0     // 0 x 1 = 0
(1 & 0) === 0     // 1 x 0 = 0
(1 & 1) === 1     // 1 x 1 = 1

Сдвиг влево (<<)

Оператор сдвига влево (<<) принимает два операнда. Первый операнд — это целое число, а второй операнд — это количество битов первого операнда, которое нужно сдвинуть влево. Нулевые (0) биты сдвигаются справа, а лишние биты, сдвинутые влево, отбрасываются.

Например, рассмотрим целое число 170. Допустим, мы хотим сдвинуться на три бита влево. Мы можем использовать оператор << следующим образом:

// 170 => 00000000000000000000000010101010

// 170 << 3
// --------------------------------------------
//    (000)00000000000000000000010101010(***)
// --------------------------------------------
//  = (***)00000000000000000000010101010(000)
// --------------------------------------------
//  = 00000000000000000000010101010000
// --------------------------------------------
//  = 1360 (decimal)

console.log(170 << 3); // 1360

Сдвиг вправо (>>)

Оператор сдвига вправо с распространением знака (>>) принимает два операнда. Первый операнд — это целое число, а второй операнд — это количество битов первого операнда, которое нужно сдвинуть вправо.

Лишние биты, сдвинутые вправо, отбрасываются, тогда как копии знакового бита (крайний левый бит) сдвигаются слева.

// 170 >> 3
// --------------------------------------------
//    (***)00000000000000000000000010101(010)
// --------------------------------------------
//  = (000)00000000000000000000000010101(***)
// --------------------------------------------
//  = 00000000000000000000000000010101
// --------------------------------------------
//  = 21 (decimal)

Побитовое ИЛИ (|)

Оператор | выполняет операцию ИЛИ над каждой парой соответствующих битов своих операндов. Оператор | возвращает 0, только если оба бита равны 0; в противном случае возвращается 1.

Вот возможные значения операции ИЛИ для пары битов:

(0 | 0) === 0
(0 | 1) === 1
(1 | 0) === 1
(1 | 1) === 1

Побитовое исключающее ИЛИ (^)

Оператор ^ выполняет операцию XOR (исключающее ИЛИ) над каждой парой соответствующих битов своих операндов. Оператор ^ возвращает 0, если оба бита одинаковы (0 или 1); в противном случае возвращается 1

(0 ^ 0) === 0
(0 ^ 1) === 1
(1 ^ 0) === 1
(1 ^ 1) === 0

Теперь давайте посмотрим на некоторые приложения побитовых операторов.

Отключение битов

Оператор & обычно используется в приложениях для маскирования битов, чтобы гарантировать, что определенные биты отключены для данной последовательности битов. Это основано на том факте, что для любого бита A:

  • (A & 0 = 0) — бит всегда отключается соответствующим битом 0
  • (A & 1 = A) — бит остается неизменным при соединении с соответствующим битом 1.

Например, у нас есть 8-битное целое число, и мы хотим убедиться, что первые 4 бита выключены (установлены в 0). Для этого можно использовать оператор &.

Проверка установленных битов

У оператора & есть и другие полезные приложения для маскирования битов. Одним из таких приложений является определение того, установлены ли один или несколько битов для данной последовательности битов. Например, предположим, что мы хотим проверить, установлен ли пятый бит для данного десятичного числа.

Четным или нечетным

Использование оператора & при проверке установленных битов для десятичного числа может быть расширено для проверки того, является ли данное десятичное число четным или нечетным. Для этого в качестве битовой маски используется 1 (чтобы определить, установлен ли первый бит или крайний правый бит).

Для целых чисел младший значащий бит (первый бит или крайний правый бит) может использоваться для определения, является ли число четным или нечетным. Если младший значащий бит включен (установлен в 1), число нечетное; в противном случае число четное.

Преобразование цвета: RGB в шестнадцатеричный

Одним из очень полезных применений оператора сдвига влево (<<) является преобразование цветов из представления RGB в шестнадцатеричное представление.

Значение цвета для каждого компонента цвета RGB находится в пределах 0 - 255. Проще говоря, каждое значение цвета может быть представлено 8 битами.