位操作符與移位運(yùn)算

位操作符用于在最近本的層次上这弧,即按內(nèi)存中表示數(shù)值的位來操作數(shù)值检眯。
ECMAScript中的所有數(shù)值都以 IEEE-754 64 位格式存儲(chǔ),但位操作符并不直接操作64位的值俯逾。而是先將64位的值轉(zhuǎn)換成32位的整數(shù),然后執(zhí)行操作舅逸,最后再將結(jié)果轉(zhuǎn)換回64位桌肴。
對(duì)于我們來說, 由于64位存儲(chǔ)格式是透明的琉历,因此整個(gè)過程就像是只存在32位的整數(shù)一樣坠七。

對(duì)于有符號(hào)的整數(shù),32位中的前31位用于表示整數(shù)的值善已。第32位用于表示數(shù)值的符號(hào):0表示正數(shù),1表示負(fù)數(shù)离例。這個(gè)表示符號(hào)的位叫做符號(hào)位换团,符號(hào)位的值決定了其他位數(shù)值的格式。其中宫蛆,正數(shù)以純二進(jìn)制格式存儲(chǔ)艘包,31位中的每一位都表示2的冪。第一位(叫做位0)表示2的0次冪耀盗,第二位表示2的1次冪想虎,以此類推。
沒有用到的位以0填充叛拷,即忽略不計(jì)舌厨。例如,數(shù)值18的二進(jìn)制表示是00000000000000000000000000010010忿薇,或者更簡潔的10010裙椭。這個(gè)5個(gè)有效位,這5位本身就決定了實(shí)際的值署浩。

負(fù)數(shù)同樣以二進(jìn)制碼存儲(chǔ)揉燃,但是用的格式是二進(jìn)制補(bǔ)碼。計(jì)算一個(gè)數(shù)值的二進(jìn)制補(bǔ)碼筋栋,需要經(jīng)過下面3個(gè)步驟:

  • 求這個(gè)數(shù)值絕對(duì)值的二進(jìn)制碼(例如炊汤,要求-18的二進(jìn)制補(bǔ)碼,先求18的二進(jìn)制碼)弊攘;
  • 求二進(jìn)制反碼抢腐,即將0替換為1,將1替換為0襟交;
  • 得到的二進(jìn)制反碼加1氓栈。
    要根據(jù)這個(gè)3個(gè)步驟求得-18的二進(jìn)制碼,首先就要求得18的二進(jìn)制碼婿着,即:
0000 0000 0000 0000 0000 0000 0001 0010

然后授瘦,求其二進(jìn)制反碼醋界,即0和1互換:

1111 1111 1111 1111 1111 1111 1110 1101

最后,二進(jìn)制反碼加1:

1111 1111 1111 1111 1111 1111 1110 1101
                                      1
---------------------------------------
1111 1111 1111 1111 1111 1111 1110 1110

這樣提完,就求得了-18的二進(jìn)制表示形纺,即11111111111111111111111111101110。需要注意的是徒欣,在處理有符號(hào)整數(shù)時(shí)逐样,是不能訪問位31的。

在ECMAScript中打肝,當(dāng)對(duì)數(shù)值應(yīng)用位操作符時(shí)脂新,后臺(tái)會(huì)發(fā)生如下轉(zhuǎn)換過程:64位的數(shù)值被轉(zhuǎn)換成32位數(shù)值,然后執(zhí)行位操作粗梭,最后再將32位的結(jié)果轉(zhuǎn)換回64位數(shù)值争便。這樣,表面上看起來就好像是在操作32位數(shù)值断医,就跟著其他語言中以類似的方式執(zhí)行二進(jìn)制操作一樣滞乙。但這個(gè)轉(zhuǎn)換過程也導(dǎo)致了一個(gè)嚴(yán)重的負(fù)效應(yīng),即在對(duì)特殊的NaNInfinity值應(yīng)用位操作時(shí)鉴嗤,這兩個(gè)值都會(huì)被當(dāng)做0來處理斩启。
如果對(duì)非數(shù)值應(yīng)用位操作符,會(huì)先使用Number()函數(shù)將該值轉(zhuǎn)換為一個(gè)數(shù)值(自動(dòng)完成)醉锅,然后在應(yīng)用位操作兔簇,得到的結(jié)果將是一個(gè)數(shù)值。

1.按位非(NOT)

按位非操作符由一個(gè)波浪線(~)表示硬耍,執(zhí)行按位非的結(jié)果就是返回?cái)?shù)值的反碼男韧。按位非是ECMAScript操作符中少數(shù)幾個(gè)與二進(jìn)制計(jì)算有關(guān)的操作符之一。如:

var num1 = 25;               //二進(jìn)制 00000000000000000000000000011001
var num2 = ~num1;            //二進(jìn)制 11111111111111111111111111100110
alert(num2);                 // -26

這里默垄,對(duì)25執(zhí)行按位非操作此虑,結(jié)果得到了-26。這也驗(yàn)證了按位非操作的本質(zhì):操作數(shù)的負(fù)值減一口锭。但是由于按位非是在數(shù)值表示的最底層執(zhí)行操作朦前,因此速度更快。

2.按位與(AND)

按位與操作符是由一個(gè)和號(hào)字符(&)表示鹃操,它有兩個(gè)操作符數(shù)韭寸。從本質(zhì)上將,按位與操作就是將兩個(gè)數(shù)值的每一位對(duì)其荆隘,然后根據(jù)下表中的規(guī)則恩伺,對(duì)相同位置上的兩個(gè)數(shù)執(zhí)行AND操作:

第一個(gè)數(shù)值的位 第二個(gè)數(shù)值的位 結(jié)果
1 1 1
1 0 0
0 1 0
0 0 0

簡而言之,按位與操作旨在兩個(gè)數(shù)值的對(duì)應(yīng)位都是1時(shí)才返回1椰拒,任何一位是0晶渠,結(jié)果都是0凰荚。
下面看一個(gè)對(duì)25和3執(zhí)行按位與操作的例子:

var result = 25 & 3;
alert(result);            // 1

其底層操作:

 25 = 0000 0000 0000 0000 0000 0000 0001 1001
  3 = 0000 0000 0000 0000 0000 0000 0000 0011
----------------------------------------------
AND = 0000 0000 0000 0000 0000 0000 0000 0001

3.按位或 (OR)

按位或操作符由一個(gè)豎線符號(hào)(|)表示,同樣也有兩個(gè)操作數(shù)褒脯。按位或操作遵循下面這個(gè)真值表:

第一個(gè)數(shù)值的位 第二個(gè)數(shù)值的位 結(jié)果
1 1 1
1 0 1
0 1 1
0 0 0

由此可見便瑟,按位或操作在有一個(gè)位是1的情況下就返回1,而只有在兩個(gè)位都是0的情況下才返回0番川。
如果在前面按位與的例子中對(duì)25和3進(jìn)行按位或操作到涂,則代碼如下:

var result = 25 | 3;
alert(result);         // 27

25與3按位或的結(jié)果是27:

 25 = 0000 0000 0000 0000 0000 0000 0001 1001
  3 = 0000 0000 0000 0000 0000 0000 0000 0011
----------------------------------------------
 OR = 0000 0000 0000 0000 0000 0000 0001 1011

4.按位異或 (XOR)

按位異或操作符由一個(gè)插入符號(hào)(^)表示,也有兩個(gè)操作數(shù)颁督,以下是按位異或的真值表:

第一個(gè)數(shù)值的位 第二個(gè)數(shù)值的位 結(jié)果
1 1 0
1 0 1
0 1 1
0 0 0

按位異或與按位或的不同之處在于践啄,這個(gè)操作在兩個(gè)數(shù)值對(duì)應(yīng)為上只有一個(gè)1時(shí)才返回1,如果對(duì)應(yīng)的兩位都是1或都是0沉御,則返回0.
對(duì)25和3執(zhí)行按位異或操作的代碼如下:

var result = 25 ^ 3;
alert(result);         // 26

其底層代碼如下:

 25 = 0000 0000 0000 0000 0000 0000 0001 1001
  3 = 0000 0000 0000 0000 0000 0000 0000 0011
----------------------------------------------
 OR = 0000 0000 0000 0000 0000 0000 0001 1010

5.左移

左移操作符由兩個(gè)小于號(hào)(<<)表示屿讽,這個(gè)操作符會(huì)將數(shù)值的所有位向左移動(dòng)指定的位數(shù)。如:

var oldVal = 2;                   //二進(jìn)制 10
var newVal = oldVal << 5;         //二進(jìn)制1000000嚷节,十進(jìn)制64
alert(newVal);                    // 64

注意聂儒,在想做移位后虎锚,原數(shù)值的右側(cè)多出了5個(gè)空位硫痰,左移操作會(huì)以0來填充這些空位,以便得到的結(jié)果是一個(gè)完整的42位二進(jìn)制數(shù)窜护。而且左移不會(huì)影響操作數(shù)的符號(hào)位效斑,換句話說,如果將-2向左移動(dòng)5位柱徙,結(jié)果將是-64缓屠,而非64。

6.有符號(hào)的右移

有符號(hào)的右移操作由兩個(gè)大于號(hào)(>>)表示护侮,這個(gè)操作符將會(huì)將數(shù)值向右移動(dòng)敌完,但保留符號(hào)位(即正負(fù)號(hào)標(biāo)記)。有符號(hào)的右移操作與左移操作恰好相反羊初,即如果將64向右移動(dòng)5位滨溉,結(jié)果將便會(huì)2。

var oldVal = 64;                   //二進(jìn)制1000000
var newVal = oldVal >> 5;         //二進(jìn)制10
alert(newVal);                    // 2

7.無符號(hào)右移

無符號(hào)右移操作符由3個(gè)大于號(hào)(>>>)表示长赞,這個(gè)操作符會(huì)將數(shù)值的所有32位都向右移動(dòng)晦攒,對(duì)正數(shù)來說,無符號(hào)右移的結(jié)果與右移相同得哆。扔以前面有符號(hào)的代碼為例脯颜,如果將64無符號(hào)右移5位,結(jié)果仍然還是2:

var oldVal = 64;                   //二進(jìn)制1000000
var newVal = oldVal >>> 5;         //二進(jìn)制10
alert(newVal);                    // 2

但是對(duì)于負(fù)數(shù)來說就不一樣了贩据。首先栋操,無符號(hào)右移是以0來填充空位闸餐,而不是像有符號(hào)右移那樣以符號(hào)位的值來填充空位。所以讼庇,對(duì)證書的無符號(hào)右移與有符號(hào)右移結(jié)果相同绎巨,但是對(duì)負(fù)數(shù)的結(jié)果就不同了。其次蠕啄,無符號(hào)有意操作符會(huì)把負(fù)數(shù)的二進(jìn)制碼當(dāng)做正數(shù)的二進(jìn)制碼场勤。而且,由于負(fù)數(shù)以其絕對(duì)值的二進(jìn)制補(bǔ)碼形式表示歼跟,因?yàn)榫蜁?huì)導(dǎo)致無符號(hào)右移后的結(jié)果非常之大和媳。

var oldVal = -64;                  // 等于二進(jìn)制的11111111111111111111111111000000
var newVal = oldVal >>> 5;         // 等于十進(jìn)制的134217726
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市哈街,隨后出現(xiàn)的幾起案子留瞳,更是在濱河造成了極大的恐慌,老刑警劉巖骚秦,帶你破解...
    沈念sama閱讀 222,183評(píng)論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件她倘,死亡現(xiàn)場離奇詭異,居然都是意外死亡作箍,警方通過查閱死者的電腦和手機(jī)硬梁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,850評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來胞得,“玉大人荧止,你說我怎么就攤上這事〗捉#” “怎么了跃巡?”我有些...
    開封第一講書人閱讀 168,766評(píng)論 0 361
  • 文/不壞的土叔 我叫張陵,是天一觀的道長牧愁。 經(jīng)常有香客問我素邪,道長,這世上最難降的妖魔是什么猪半? 我笑而不...
    開封第一講書人閱讀 59,854評(píng)論 1 299
  • 正文 為了忘掉前任兔朦,我火速辦了婚禮,結(jié)果婚禮上办龄,老公的妹妹穿的比我還像新娘烘绽。我一直安慰自己,他們只是感情好俐填,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,871評(píng)論 6 398
  • 文/花漫 我一把揭開白布安接。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪盏檐。 梳的紋絲不亂的頭發(fā)上歇式,一...
    開封第一講書人閱讀 52,457評(píng)論 1 311
  • 那天,我揣著相機(jī)與錄音胡野,去河邊找鬼材失。 笑死,一個(gè)胖子當(dāng)著我的面吹牛硫豆,可吹牛的內(nèi)容都是我干的龙巨。 我是一名探鬼主播,決...
    沈念sama閱讀 40,999評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼熊响,長吁一口氣:“原來是場噩夢啊……” “哼旨别!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起汗茄,我...
    開封第一講書人閱讀 39,914評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤秸弛,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后洪碳,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體递览,經(jīng)...
    沈念sama閱讀 46,465評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,543評(píng)論 3 342
  • 正文 我和宋清朗相戀三年瞳腌,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了绞铃。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,675評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡纯趋,死狀恐怖憎兽,靈堂內(nèi)的尸體忽然破棺而出冷离,到底是詐尸還是另有隱情吵冒,我是刑警寧澤,帶...
    沈念sama閱讀 36,354評(píng)論 5 351
  • 正文 年R本政府宣布西剥,位于F島的核電站痹栖,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏瞭空。R本人自食惡果不足惜揪阿,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,029評(píng)論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望咆畏。 院中可真熱鬧南捂,春花似錦、人聲如沸旧找。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,514評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽钮蛛。三九已至鞭缭,卻和暖如春剖膳,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背岭辣。 一陣腳步聲響...
    開封第一講書人閱讀 33,616評(píng)論 1 274
  • 我被黑心中介騙來泰國打工吱晒, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人沦童。 一個(gè)月前我還...
    沈念sama閱讀 49,091評(píng)論 3 378
  • 正文 我出身青樓仑濒,卻偏偏與公主長得像,于是被迫代替她去往敵國和親偷遗。 傳聞我的和親對(duì)象是個(gè)殘疾皇子躏精,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,685評(píng)論 2 360

推薦閱讀更多精彩內(nèi)容

  • 現(xiàn)實(shí)是不能以個(gè)人意志為轉(zhuǎn)移的。誰如果要離開自己的現(xiàn)實(shí)鹦肿,就等于要離開地球矗烛。一個(gè)人應(yīng)該有理想,甚至有幻想箩溃,但他不...
    天鵬元帥666閱讀 1,857評(píng)論 0 1
  • 小寒瞭吃,小寒, 北風(fēng)牽走我歲月的嬋娟涣旨, 卻不見雪花來憐我的孤單歪架, 霧霾壓垮我綿綿的思念, 聽不見朋友遠(yuǎn)方的呼喚霹陡。 茶...
    曹煥甫閱讀 248評(píng)論 1 1
  • 一瞬間 網(wǎng)絡(luò)開始運(yùn)行了 全世界低頭以盼 夢想的的風(fēng)帆 緩緩走過 染上糜爛的沼澤 多少秀麗的山河 被人的眼睛蒙住了磅...
    屋頂有故事的貓閱讀 275評(píng)論 1 3
  • 第一和蚪,如何嘗試搞一個(gè)創(chuàng)作? 受傷的梵高
    fd37092b38f1閱讀 289評(píng)論 0 0