Бітові оператори

Бітові оператори опрацьовують свої операнди як послідовність 32-х бітів (нулів та одиниць), а не як десяткові, шістнадцяткові чи вісімкові числа. Наприклад, десяткове число дев'ять має бітове представлення 1001. Бітові оператори виконують операції над цими бітовими представленнями, але повертають стандартні числові значення JavaScript.

Наступна таблиця наводить перелік бітових операторів JavaScript:

Оператор Застосування Опис
Побітове І (AND) a & b Повертає 1 на кожній позиції, де відповідні біти обох операндів дорівнюють 1.
Побітове АБО (OR) a | b Повертає 1 на кожній позиції, де відповідні біти одного чи обох операндів дорівнюють 1.
Виключне побітове АБО (XOR) a ^ b Повертає 1 на кожній позиції, де відповідний біт одного з двох, але не обох, операндів дорівнює 1.
Побітове НЕ (NOT) ~ a Виконує інверсію бітів операнду.
Лівий зсув a << b Зсуває a у двійковому представленні на b (< 32) бітів ліворуч, заповнюючи позиції справа нулями.
Правий зсув з розширенням знаку a >> b Зсуває a у двійковому представленні на b (< 32) бітів праворуч, відкидаючи зсунуті біти.
Правий зсув із заповненням нулями a >>> b   Зсуває a у двійковому представленні на b (< 32) бітів праворуч, відкидаючи зсунуті біти та заповнюючи позиції зліва нулями.

32-бітні цілі числа зі знаком

Операнди усіх бітових операторів перетворюються на 32-бітні цілі числа зі знаком у форматі доповняльного коду, окрім оператора правого зсуву із заповненням нулями, який повертає беззнакове ціле 32-бітне число. Формат доповняльного коду означає, що від'ємний еквівалент числа (наприклад, 5 та -5) - це інвертовані біти числа (побітове НЕ, або обернений код числа) плюс один. Для прикладу, наступний код представляє ціле число 314:

00000000000000000000000100111010

Наступний код представляє ~314, тобто, обернений код числа 314:

11111111111111111111111011000101

Нарешті, наступний код представляє доповняльний код числа -314:

11111111111111111111111011000110

Доповняльний код гарантує, що лівий біт дорівнює 0, коли число є додатним, і 1, коли число є від'ємним. Тому він відомий як знаковий біт.

Число 0 є цілим числом, усі біти якого дорівнюють 0.

0 (основа 10) = 00000000000000000000000000000000 (основа 2)

Число -1 є цілим числом, усі біти якого дорівнюють 1.

-1 (основа 10) = 11111111111111111111111111111111 (основа 2)

Число -2147483648 (шістнадцяткове представлення: -0x80000000) є цілим числом, усі біти якого дорівнюють 0, окрім першого (старшого) біта.

-2147483648 (основа 10) = 10000000000000000000000000000000 (основа 2)

Число 2147483647 (шістнадцяткове представлення: 0x7fffffff) є цілим числом, усі біти якого дорівнюють 1, окрім першого (старшого) біта.

2147483647 (основа 10) = 01111111111111111111111111111111 (основа 2)

Числа -2147483648 та 2147483647 є мінімальним та максимальним цілими числами, які можуть бути представлені 32-бітним знаковим числом.

Побітові логічні оператори

Концептуально побітові логічні оператори працюють наступним чином:

  • Операнди перетворюються на 32-бітні цілі числа та виражаються послідовністю бітів (нулів та одиниць). Числа, що мають більше 32 бітів, втрачають свої старші біти. Наприклад, наступне ціле число, що має більше 32 бітів, буде перетворено на 32-бітне ціле число:
    До:     11100110111110100000000000000110000000000001
    Після:              10100000000000000110000000000001
  • Кожен біт першого операнду ставиться у пару до відповідного біту другого операнду: перший біт до першого біту, другий біт до другого, і так далі.
  • Оператор застосовується до кожної пари бітів, а результат будується побітово.

& (Побітове І)

Виконує операцію І (AND) над кожною парою бітів. a І b дає 1 тільки якщо обидва, a та b, дорівнюють 1. Таблиця істинності для операції І наступна:

a b a AND b
0 0 0
0 1 0
1 0 0
1 1 1
.    9 (основа 10) = 00000000000000000000000000001001 (основа 2)
    14 (основа 10) = 00000000000000000000000000001110 (основа 2)
                   --------------------------------
14 & 9 (основа 10) = 00000000000000000000000000001000 (основа 2) = 8 (основа 10)

Побітове І над будь-яким числом x та 0 дає 0.

| (Побітове АБО)

Виконує операцію АБО (OR) над кожною парою бітів. a АБО b дає 1, якщо або a, або b дорівнює 1. Таблиця істинності для операції АБО наступна:

a b a OR b
0 0 0
0 1 1
1 0 1
1 1 1
.    9 (основа 10) = 00000000000000000000000000001001 (основа 2)
    14 (основа 10) = 00000000000000000000000000001110 (основа 2)
                   --------------------------------
14 | 9 (основа 10) = 00000000000000000000000000001111 (основа 2) = 15 (основа 10)

Побітове АБО над будь-яким числом x та 0 дає x.

^ (Виключне побітове АБО)

Виконує операцію виключного АБО (XOR) над кожною парою бітів. a викл. АБО b дає 1, якщо a та b є різними. Таблиця істинності для операції XOR наступна:

a b a XOR b
0 0 0
0 1 1
1 0 1
1 1 0
.    9 (основа 10) = 00000000000000000000000000001001 (основа 2)
    14 (основа 10) = 00000000000000000000000000001110 (основа 2)
                   --------------------------------
14 ^ 9 (основа 10) = 00000000000000000000000000000111 (основа 2) = 7 (основа 10)

Виключне побітове АБО над будь-яким числом x та 0 дає x.

~ (Побітове НЕ)

Виконує операцію НЕ над кожним бітом. НЕ a повертає інвертоване значення (або обернений код) операнду a. Таблиця істинності для операції НЕ наступна:

a NOT a
0 1
1 0
 9 (основа 10) = 00000000000000000000000000001001 (основа 2)
               --------------------------------
~9 (основа 10) = 11111111111111111111111111110110 (основа 2) = -10 (основа 10)

Побітове НЕ над будь-яким числом x дає -(x + 1). Наприклад, ~-5 дорівнює 4.

Зауважте, що через використання 32-бітного представлення чисел і ~-1, і ~4294967295 (232-1) повернуть 0.

Оператори бітового зсуву

Оператори бітового зсуву приймають два операнди: перший є величиною, в якій треба виконати зсув, а другий вказує кількість бітових позицій для зсуву. Напрямок операції зсуву контролюється застосованим оператором.

Оператори зсуву перетворюють свої операнди на 32-бітні цілі числа у порядку від старшого до молодшого байту та повертають результат того самого типу, до якого належить лівий операнд. Лише молодші п'ять бітів правого операнду будуть використані.

<< (Лівий зсув)

Цей оператор виконує зсув першого операнду на вказану кількість бітів ліворуч. Надлишкові біти, зсунуті ліворуч, відкидаються. Біти, додані справа, заповнюються нулями.

Наприклад, 9 << 2 дорівнює 36:

.    9 (основа 10): 00000000000000000000000000001001 (основа 2)
                  --------------------------------
9 << 2 (основа 10): 00000000000000000000000000100100 (основа 2) = 36 (основа 10)

Бітовий зсув будь-якого числа x ліворуч на y бітів дорівнює x * 2 ** y.
Отже, для прикладу: 9 << 3 можна перекласти як: 9 * (2 ** 3) = 9 * (8) = 72.

>> (Правий зсув з розширенням знаку)

Цей оператор виконує зсув першого операнду на вказану кількість бітів праворуч. Надлишкові біти, зсунуті праворуч, відкидаються. Біти, додані зліва, заповнюються значенням старшого біта. Оскільки новий старший біт матиме те саме значення, що й попередній старший біт, знаковий (старший) біт не змінюється. Звідси назва "з розширенням знаку".

Наприклад, 9 >> 2 дорівнює 2:

.    9 (основа 10): 00000000000000000000000000001001 (основа 2)
                  --------------------------------
9 >> 2 (основа 10): 00000000000000000000000000000010 (основа 2) = 2 (основа 10)

Аналогічно, -9 >> 2 дорівнює -3, оскільки знак зберігається:

.    -9 (основа 10): 11111111111111111111111111110111 (основа 2)
                   --------------------------------
-9 >> 2 (основа 10): 11111111111111111111111111111101 (основа 2) = -3 (основа 10)

>>> (Правий зсув із заповненням нулями)

Цей оператор виконує зсув першого операнду на вказану кількість бітів праворуч. Надлишкові біти, зсунуті праворуч, відкидаються. Біти, додані зліва, заповнюються нулями. Знаковий біт отримує значення 0, а отже, результат завжди невід'ємний. На відміну від інших бітових операторів, правий зсув із заповненням нулями повертає беззнакове ціле 32-бітне число.

Для невід'ємних чисел, правий зсув із заповненням нулями та правий зсув з розширенням знаку дають однаковий результат. Наприклад, 9 >>> 2 дорівнює 2, так само, як 9 >> 2:

.     9 (основа 10): 00000000000000000000000000001001 (основа 2)
                   --------------------------------
9 >>> 2 (основа 10): 00000000000000000000000000000010 (основа 2) = 2 (основа 10)

Однак, це не одне й те саме для від'ємних чисел. Наприклад, -9 >>> 2 поверне 1073741821, що відрізняється від -9 >> 2 (що дорівнює -3):

.     -9 (основа 10): 11111111111111111111111111110111 (основа 2)
                    --------------------------------
-9 >>> 2 (основа 10): 00111111111111111111111111111101 (основа 2) = 1073741821 (основа 10)

Приклади

Прапори та бітові маски

Побітові логічні оператори часто використовуються для створення, маніпулювання та читання послідовностей прапорів, які грають роль двійкових змінних. Замість цих послідовностей можуть використовуватись зміні, але двійкові прапори займають набагато менше пам'яті (у 32 рази).

Припустимо, є 4 прапори:

  • прапор A: ми маємо проблему з мурахами
  • прапор B: ми маємо кажана
  • прапор C: ми маємо кота
  • прапор D: ми маємо качку

Ці прапори представлені послідовністю бітів: DCBA. Коли прапор встановлений, він має значення 1. Коли прапор очищений, він має значення 0. Припустимо, змінна flags має двійкове значення 0101:

var flags = 5;   // двійкове значення 0101

Це значення вказує:

  • прапор A дорівнює true (ми маємо проблему з мурахами);
  • прапор B дорівнює false (ми не маємо кажана);
  • прапор C дорівнює true (ми маємо кота);
  • прапор D дорівнює false (ми не маємо качки);

Оскільки бітові операнди 32-бітні, 0101 насправді дорівнює 00000000000000000000000000000101, але нулями попереду можна знехтувати, оскільки вони не містять корисної інформації.

Бітова маска - це послідовність бітів, які можуть маніпулювати прапорами та/або читати їх. Зазвичай, визначається "примітивна" бітова маска для кожного прапора:

var FLAG_A = 1; // 0001
var FLAG_B = 2; // 0010
var FLAG_C = 4; // 0100
var FLAG_D = 8; // 1000

Нові бітові маски можуть створюватись застовуванням побітових логічних операторів до цих примітивних бітових масок. Наприклад, бітова маска 1011 може бути створена операцією АБО з прапорів FLAG_A, FLAG_B та FLAG_D:

var mask = FLAG_A | FLAG_B | FLAG_D; // 0001 | 0010 | 1000 => 1011

Індивідуальні значення прапорів можна витягнути застосуванням операції І до них та бітової маски, де кожний біт, що має значення один, "витягне" відповідний прапор. Бітова маска маскує невідповідні прапори, об'єднуючи їх операцією І з нулями (звідси термін "бітова маска"). Наприклад, бітову маску 0100 можна використати, щоб побачити, чи встановлений прапор C:

// якщо ми маємо кота
if (flags & FLAG_C) { // 0101 & 0100 => 0100 => true
   // зробити щось
}

Бітова маска з кількома встановленими прапорами діє як "або/або". Для прикладу, наступні два фрагменти еквівалентні:

// якщо ми маємо кажана або ми маємо кота
// (0101 & 0010) || (0101 & 0100) => 0000 || 0100 => true
if ((flags & FLAG_B) || (flags & FLAG_C)) {
   // зробити щось
}
// якщо ми маємо кажана або кота
var mask = FLAG_B | FLAG_C; // 0010 | 0100 => 0110
if (flags & mask) { // 0101 & 0110 => 0100 => true
   // зробити щось
}

Прапори можна встановити, об'єднавши їх операцією АБО з бітовою маскою, де кожний біт, що має значення один, встановить відповідний прапор, якщо прапор ще не встановлений. Наприклад, бітову маску 1100 можна використати, щоб встановити прапори C та D:

// так, ми маємо кота та качку
var mask = FLAG_C | FLAG_D; // 0100 | 1000 => 1100
flags |= mask;   // 0101 | 1100 => 1101

Прапори можна очистити, об'єднавши їх операцією І з бітовою маскою, де кожний біт, що має значення нуль, очистить відповідний прапор, якщо він ще не очищений. Ця бітова маска може бути створена застосуванням операції НЕ до примітивних бітових масок. Наприклад, бітову маску 1010 можна використати, щоб очистити прапори A та C:

// ні, ми не маємо проблеми з мурахами або кота
var mask = ~(FLAG_A | FLAG_C); // ~0101 => 1010
flags &= mask;   // 1101 & 1010 => 1000

Маску також можна створити за допомогою ~FLAG_A & ~FLAG_C (правило де Моргана):

// ні, ми не маємо проблеми з мурахами і ми не маємо кота
var mask = ~FLAG_A & ~FLAG_C;
flags &= mask;   // 1101 & 1010 => 1000

Прапори можна перемикати, об'єднуючи їх операцією виключне АБО з бітовою маскою, де кожний біт, що має значення один, переключить відповідний прапор. Наприклад, бітову маску 0110 можна використати, щоб переключити прапори B та C:

// якщо ми не мали кажана, тепер ми його маємо, 
// а якщо він в нас був, бувай, кажанчику
// те саме для котів
var mask = FLAG_B | FLAG_C;
flags = flags ^ mask;   // 1100 ^ 0110 => 1010

Нарешті, усі прапори можна перевернути оператором НЕ:

// входимо у паралельний всесвіт...
flags = ~flags;    // ~1010 => 0101

Перетворення типів

Перетворити двійковий рядок на десяткове число:

var sBinString = '1011';
var nMyNumber = parseInt(sBinString, 2);
alert(nMyNumber); // виводить 11, тобто 1011

Перетворити десяткове число на двійковий рядок:

var nMyNumber = 11;
var sBinString = nMyNumber.toString(2);
alert(sBinString); // виводить 1011, тобто 11

Автоматизація створення маски

Ви можете створювати маски з набору булевих значень наступним чином:

function createMask() {
  var nMask = 0, nFlag = 0, nLen = arguments.length > 32 ? 32 : arguments.length;
  for (nFlag; nFlag < nLen; nMask |= arguments[nFlag] << nFlag++);
  return nMask;
}
var mask1 = createMask(true, true, false, true); // 11, тобто: 1011
var mask2 = createMask(false, false, true); // 4, тобто: 0100
var mask3 = createMask(true); // 1, тобто: 0001
// і т.д.

alert(mask1); // виводить 11, тобто: 1011

Зворотний алгоритм: отримання масиву булевих значень з маски

Якщо ви бажаєте створити масив булевих значень з маски, можете скористатись цим кодом:

function arrayFromMask(nMask) {
  // Значенння nMask має бути між -2147483648 та 2147483647
  if (nMask > 0x7fffffff || nMask < -0x80000000) { 
    throw new TypeError('arrayFromMask - out of range'); 
  }
  for (var nShifted = nMask, aFromMask = []; nShifted; 
       aFromMask.push(Boolean(nShifted & 1)), nShifted >>>= 1);
  return aFromMask;
}

var array1 = arrayFromMask(11);
var array2 = arrayFromMask(4);
var array3 = arrayFromMask(1);

alert('[' + array1.join(', ') + ']');
// виводить "[true, true, false, true]", тобто: 11, тобто: 1011

Ви можете перевірити обидва алгоритми одночасно…

var nTest = 19; // наша користувацька маска
var nResult = createMask.apply(this, arrayFromMask(nTest));

alert(nResult); // 19

Суто з навчальною метою (оскільки існує метод Number.toString(2)) ми показуємо, як можна модифікувати алгоритм arrayFromMask для створення рядка, що містить двійкове представлення числа, а не масиву булевих значень:

function createBinaryString(nMask) {
  // Значення nMask має бути між -2147483648 та 2147483647
  for (var nFlag = 0, nShifted = nMask, sMask = ''; nFlag < 32;
       nFlag++, sMask += String(nShifted >>> 31), nShifted <<= 1);
  return sMask;
}

var string1 = createBinaryString(11);
var string2 = createBinaryString(4);
var string3 = createBinaryString(1);

alert(string1);
// виводить 00000000000000000000000000001011, тобто 11

Специфікації

Специфікація Статус Коментар
ECMAScript 1st Edition (ECMA-262) Standard Початкове визначення.
ECMAScript 5.1 (ECMA-262) Standard Визначені у кількох розділах специфікації: Побітовий оператор НЕ, Бітові оператори зсуву, Двійкові побітові оператори
ECMAScript 2015 (6th Edition, ECMA-262) Standard Визначені у кількох розділах специфікації: Побітовий оператор НЕ, Бітові оператори зсуву, Двійкові побітові оператори
ECMAScript Latest Draft (ECMA-262) Draft Визначені у кількох розділах специфікації: Побітовий оператор НЕ, Бітові оператори зсуву, Двійкові побітові оператори

Сумісність з веб-переглядачами

Update compatibility data on GitHub
DesktopMobileServer
ChromeEdgeFirefoxInternet ExplorerOperaSafariAndroid webviewChrome for AndroidFirefox for AndroidOpera for AndroidSafari on iOSSamsung InternetNode.js
Bitwise AND (a & b)Chrome Full support 1Edge Full support 12Firefox Full support 1IE Full support 3Opera Full support YesSafari Full support YesWebView Android Full support 1Chrome Android Full support 18Firefox Android Full support 4Opera Android Full support YesSafari iOS Full support YesSamsung Internet Android Full support 1.0nodejs Full support Yes
Bitwise left shift (a << b)Chrome Full support 1Edge Full support 12Firefox Full support 1IE Full support 3Opera Full support YesSafari Full support YesWebView Android Full support 1Chrome Android Full support 18Firefox Android Full support 4Opera Android Full support YesSafari iOS Full support YesSamsung Internet Android Full support 1.0nodejs Full support Yes
Bitwise NOT (~a)Chrome Full support 1Edge Full support 12Firefox Full support 1IE Full support 3Opera Full support YesSafari Full support YesWebView Android Full support 1Chrome Android Full support 18Firefox Android Full support 4Opera Android Full support YesSafari iOS Full support YesSamsung Internet Android Full support 1.0nodejs Full support Yes
Bitwise OR (a | b)Chrome Full support 1Edge Full support 12Firefox Full support 1IE Full support 3Opera Full support YesSafari Full support YesWebView Android Full support 1Chrome Android Full support 18Firefox Android Full support 4Opera Android Full support YesSafari iOS Full support YesSamsung Internet Android Full support 1.0nodejs Full support Yes
Bitwise right shift (a >> b)Chrome Full support 1Edge Full support 12Firefox Full support 1IE Full support 3Opera Full support YesSafari Full support YesWebView Android Full support 1Chrome Android Full support 18Firefox Android Full support 4Opera Android Full support YesSafari iOS Full support YesSamsung Internet Android Full support 1.0nodejs Full support Yes
Bitwise unsigned right shift (a >>> b)Chrome Full support 1Edge Full support 12Firefox Full support 1IE Full support 3Opera Full support YesSafari Full support YesWebView Android Full support 1Chrome Android Full support 18Firefox Android Full support 4Opera Android Full support YesSafari iOS Full support YesSamsung Internet Android Full support 1.0nodejs Full support Yes
Bitwise XOR (a ^ b)Chrome Full support 1Edge Full support 12Firefox Full support 1IE Full support 3Opera Full support YesSafari Full support YesWebView Android Full support 1Chrome Android Full support 18Firefox Android Full support 4Opera Android Full support YesSafari iOS Full support YesSamsung Internet Android Full support 1.0nodejs Full support Yes

Legend

Full support  
Full support

Див. також