前面咱們已經瞭解了六大位操做符(&
|
~
^
<<
>>
)的用法(javascript 位運算),也整理了一些經常使用的位運算操做(經常使用位運算整理),本文咱們繼續深刻位運算,來了解下二進制的經典應用-標誌位與掩碼。javascript
位運算常常被用來建立、處理以及讀取標誌位序列——一種相似二進制的變量。雖然可使用變量代替標誌位序列,可是這樣能夠節省內存(1/32)。html
例若有4個標誌位:java
標誌位經過位序列DCBA來表示,當一個位置被置爲1時,表示有該項,置爲0時,表示沒有該項。例如一個變量flag=9,二進制表示爲1001,就表示咱們有D和A。app
掩碼 (bitmask) 是一個經過與/或來讀取標誌位的位序列。典型的定義每一個標誌位的原語掩碼以下:code
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 邏輯或獲得:htm
var mask = FLAG_A | FLAG_B | FLAG_D; // 0001 | 0010 | 1000 => 1011
某個特定的位能夠經過與掩碼作邏輯與運算獲得,經過與掩碼的與運算能夠去掉無關的位,獲得特定的位。例如,掩碼 0100 能夠用來檢查標誌位 C 是否被置位:(核心就是判斷某位上的數 參考經常使用位運算整理 下同)blog
// 若是咱們有 banana if (flags & FLAG_C) { // 0101 & 0100 => 0100 => true // do stuff }
一個有多個位被置位的掩碼錶達任一/或者的含義。例如,如下兩個表達是等價的:ip
// 若是咱們有 apple 或者 banana 至少一個 // (0101 & 0010) || (0101 & 0100) => 0000 || 0100 => true if ((flags & FLAG_B) || (flags & FLAG_C)) { // do stuff } var mask = FLAG_B | FLAG_C; // 0010 | 0100 => 0110 if (flags & mask) { // 0101 & 0110 => 0100 => true // do stuff }
能夠經過與掩碼作或運算設置標誌位,掩碼中爲 1 的位能夠設置對應的位。例如掩碼 1100 可用來設置位 C 和 D:(核心就是將某位變爲1 )內存
// 咱們有 banana 和 pear var mask = FLAG_C | FLAG_D; // 0100 | 1000 => 1100 flags |= mask; // 0101 | 1100 => 1101
能夠經過與掩碼作與運算清除標誌位,掩碼中爲 0 的位能夠設置對應的位。掩碼能夠經過對原語掩碼作非運算獲得。例如,掩碼 1010 能夠用來清除標誌位 A 和 C :(核心就是將某位變爲0)get
// 咱們沒有 orange 也沒有 banana var mask = ~(FLAG_A | FLAG_C); // ~0101 => 1010 flags &= mask; // 1101 & 1010 => 1000
如上的掩碼一樣能夠經過 ~FLAG_A & ~FLAG_C 獲得(德摩根定律):
// 咱們沒有 orange 也沒有 banana var mask = ~FLAG_A & ~FLAG_C; flags &= mask; // 1101 & 1010 => 1000
標誌位可使用異或運算切換。全部值爲 1 的爲能夠切換對應的位。例如,掩碼 0110 能夠用來切換標誌位 B 和 C:(核心就是將某位取反)
// 若是咱們之前沒有 apple ,那麼咱們如今有 apple // 可是若是咱們已經有了一個,那麼如今沒有了 // 對 banana 也是相同的狀況 var mask = FLAG_B | FLAG_C; flags = flags ^ mask; // 1100 ^ 0110 => 1010
最後,全部標誌位能夠經過非運算翻轉:
// entering parallel universe... flags = ~flags; // ~1010 => 0101