JavaScriptのビット演算・シフト演算を超やさしく
難しく見える「ビット演算」は、数字を0と1の並びにして、スイッチのON/OFFみたいに扱うだけ。ふだん使わなくても「なるほど!」が増えるし、フラグ管理や高速処理で役立ちます。例題と図解でかみ砕いていきます。
数字をビットで見るってどういうこと?
- 2進数とは: 10進数の「13」は、2進数だと「1101」。1はON、0はOFFのイメージ。
- JavaScriptでの前提: ビット演算するとき、数値は自動的に32ビット整数に変換されます。小数は切り捨てて扱われます。
- 例: 13 と 9 を2進数にしてみる
- 13 → 1101
- 9 → 1001
ヒント:2進数は慣れるまで深追いしなくてOK。「1はON、0はOFF」くらいの感覚で進めましょう。
4つのビット演算子を例で理解する
AND &(両方1なら1)
- イメージ: 二人が同時にスイッチONならON。
- 例題: 13 & 9
- 13: 1101
- 9 : 1001
- AND: 1001 → 10進数で 9
console.log(13 & 9); // 9
JavaScriptOR |(どちらか1なら1)
- イメージ: どちらかがスイッチONならON。
- 例題: 13 | 9
- 1101
- 1001
- OR: 1101 → 13
console.log(13 | 9); // 13
JavaScriptXOR ^(片方だけ1なら1)
- イメージ: 「違っていたらON」同じならOFF。
- 例題: 13 ^ 9
- 1101
- 1001
- XOR: 0100 → 4
console.log(13 ^ 9); // 4
JavaScriptNOT ~(反転:0→1、1→0)
- イメージ: 全部ひっくり返す。
- 注意: 負の数っぽい結果になるのは「2の補数」という表現のため。
- 例題: ~13
console.log(~13); // -14
// 理由:…00001101 を反転すると …11110010(= -14)になる
JavaScript3つのシフト演算子を例で理解する
左シフト <<(左にずらす。右端は0で埋める)
- イメージ: 10進数でいう「×2」をビットでやる感じ。
- 例題: 3 << 1
- 3: 0011 → 左に1シフト → 0110(= 6)
console.log(3 << 1); // 6
console.log(3 << 2); // 12 (さらに×2)
JavaScript右シフト >>(符号あり。左端は符号で埋める)
- イメージ: 右にずらして小さくする。負の数は負のまま。
- 例題: 12 >> 1
- 12: 1100 → 0110(= 6)
console.log(12 >> 1); // 6
console.log(12 >> 2); // 3
JavaScript- 負の数の例: -8 >> 1 は符号を保つ
console.log(-8 >> 1); // -4
JavaScript右シフト(符号なし) >>>(左端は常に0)
- イメージ: 負の数でも「符号」を無視して0を入れる。結果は非負(0以上)。
- 例題: -8 >>> 1
console.log(-8 >>> 1); // 2147483644
// 大きな数になるのは、内部のビット表現を「正の数」として解釈するため
JavaScript手を動かすミニ練習(よくある使い方)
1. フラグ管理(ON/OFFをまとめて持つ)
- 状況: 「通知ON」「ダークモードON」「位置情報OFF」を1つの数で持ちたい。
- 割り当て:
- 通知: 1番目ビット → 0001
- ダークモード: 2番目ビット → 0010
- 位置情報: 3番目ビット → 0100
まとめて状態を作る(ORでON)
const FLAG_NOTIFY = 1; // 0001
const FLAG_DARK = 1 << 1; // 0010
const FLAG_GPS = 1 << 2; // 0100
let settings = 0;
settings = settings | FLAG_NOTIFY; // 通知ON -> 0001
settings = settings | FLAG_DARK; // ダークON -> 0011
// 位置情報はOFF -> 0011 のまま
console.log(settings); // 3
JavaScript特定のフラグがONかチェック(AND)
const isDarkOn = (settings & FLAG_DARK) !== 0;
console.log(isDarkOn); // true
JavaScriptフラグをOFFにする(AND+NOT)
// 通知をOFFにする
settings = settings & ~FLAG_NOTIFY; // 0011 & 1110 = 0010
console.log(settings); // 2
JavaScript2. 奇数・偶数判定(最下位ビットを見る)
- 最下位ビットが1なら奇数、0なら偶数。
function isOdd(n) {
return (n & 1) === 1;
}
console.log(isOdd(7)); // true
console.log(isOdd(12)); // false
JavaScript3. 高速な掛け算・割り算(2のべき乗ならシフトが速い)
console.log(5 << 1); // 10 (×2)
console.log(5 << 3); // 40 (×8)
console.log(40 >> 2); // 10 (÷4)
JavaScriptつまずきポイントの先回りQ&A
- Qなぜ ~ の結果がマイナスなの?
- A
32ビットの「2の補数」表現で反転すると、符号も含めてひっくり返るからです。実用では「~x は -(x+1) と同じ」と覚えるとラクです。
console.log(~x === -(x + 1)); // ほぼ常に true
JavaScript- Q>> と >>> はどう使い分ける?
- A
負の数を扱うなら「>>」(符号を保つ)。符号を無視して純粋にビットを右に詰めたいなら「>>>」。
- Q32ビットって意識した方がいい?
- A
端的には「ビット演算は32ビットに丸められる」と覚えておけば十分。巨大な数や小数はビット演算に向きません。
まとめ(ここだけ押さえればOK)
- 基本4種:
&(両方1)、|(どちらか1)、^(違えば1)、~(反転) - シフト3種:
<<(左に詰める)、>>(符号あり右)、>>>(符号なし右) - 実用ミニ技: フラグ管理、奇数判定、2のべき乗の掛け算・割り算
- 負の数の注意:
>>は負を保つ、>>>は0で埋めて非負になる
