JavaScript 位運(yùn)算符
JavaScript 在日常的應(yīng)用中非常的少,其實當(dāng)年在大學(xué)學(xué)習(xí)C#的時候,位運(yùn)算符也不是重點,而且后來考試的時候根本就沒有考這章,但是對于對數(shù)字感興趣的我,當(dāng)時聽的特認(rèn)真,以至于雖然從來都沒再看過,印象還是非常的深刻,前幾天在用的時候進(jìn)入了個誤區(qū),所以這里還是記錄一下,鞏固一下哈~
JavaScript 的位運(yùn)算符一共有7個,分別是&、|、^、~、<<、>>、>>>(C#沒有這個運(yùn)算符,但是C#可以通過>>的邏輯右移來實現(xiàn)此運(yùn)算),位運(yùn)算的操作都是通過二進(jìn)制進(jìn)行的。
按位與運(yùn)算符(&)
當(dāng)兩個數(shù)相同位都為1時返回1,否則返回0,例如1&2=0,1的二進(jìn)制表示為0001,2的二進(jìn)制表示為0010,二者的運(yùn)算則返回0000。
按位或運(yùn)算符(|)
當(dāng)兩個數(shù)相同位數(shù)字不同的時候返回1,否則返回0,例如1|2=3。
按位異或運(yùn)算符(^)
當(dāng)兩個數(shù)相同位僅有一個為1的時候返回1,否則返回0,例如1^2=3。
按位非運(yùn)算符(~)
~是一個一元運(yùn)算符,它將所有位數(shù)取反。這里首先必須要說下負(fù)數(shù)的存儲,負(fù)數(shù)是以其正數(shù)的二進(jìn)制補(bǔ)碼進(jìn)行存儲的,所以我們在進(jìn)行負(fù)數(shù)的運(yùn)算時,必須要正確的獲取其二進(jìn)制編碼,也就是其正數(shù)的二進(jìn)制補(bǔ)碼。補(bǔ)碼是取反然后加1來實現(xiàn),下面看例子:
先計算3的反碼:3的二進(jìn)制形式為00000011,其反碼為11111100,其補(bǔ)碼為11111101,所以-3的二進(jìn)制編碼為11111101,那么我們要求~-3,就是取其反碼,為00000010,這就是-3的反碼,將其轉(zhuǎn)化為十進(jìn)制為2。
多試幾個就會發(fā)現(xiàn),其實一個數(shù)的反碼就是其十進(jìn)制的相反數(shù)減去1。
左移運(yùn)算符(<<)
左移運(yùn)算符就是將數(shù)的所有位集體左移,第一位變成第二位,第二位變成第三位。。。空出的新位用0補(bǔ)充。比如1<<2=4,-1<<2=-4。1的二進(jìn)制表示為0000 0001,那么將其向左移動兩位變成了0000 0100,轉(zhuǎn)換為十進(jìn)制就為4,-1的二進(jìn)制表示為1111 1111,將其向左移動兩位,得到1111 1100,1開頭的為負(fù)數(shù),將其轉(zhuǎn)化為十進(jìn)制則需要倒著執(zhí)行一次補(bǔ)碼的計算,就是先減去1,得到1111 1011,然后取反,得到0000 0100,轉(zhuǎn)化為十進(jìn)制加負(fù)號得到4。這里需要注意下二進(jìn)制的減法運(yùn)算法則:1-1=0-0=0,1-0=1,0-1=1(向高位借)。
這里我們可以發(fā)現(xiàn)左移運(yùn)算就是將其十進(jìn)制數(shù)乘以2的位數(shù)次方。
帶符號的右移運(yùn)算符(>>)
既然左移是乘以2,那么右移肯定應(yīng)該是除以2了,事實上就是這樣子的,如果數(shù)字本身為正數(shù),則在高位補(bǔ)0,如果為負(fù)數(shù)則在高位補(bǔ)1。例如3>>1=1,-3>>1=-2。3的二進(jìn)制編碼表示為0000 0011,將其向右移動1位,得到0000 0001,轉(zhuǎn)換為十進(jìn)制就是1,-3的二進(jìn)制編碼為1111 1101,將其向右移動1位得到1111 1110,這是一個負(fù)數(shù),負(fù)數(shù)轉(zhuǎn)化為十進(jìn)制,先減一得到1111 1101,取反為0000 0010,得到-2。
帶符號的右移運(yùn)算就是將其十進(jìn)制數(shù)除以2的位數(shù)次方,并舍棄余數(shù)。
無符號的右移運(yùn)算符(>>>)
正數(shù)的無符號右移運(yùn)算結(jié)果跟帶符號的右移運(yùn)算是一樣的,主要是負(fù)數(shù)的無符號右移運(yùn)算。它跟帶符號的右移的區(qū)別就在于,不管是正數(shù)還是負(fù)數(shù),高位都以0補(bǔ)充,所以對正數(shù)來說帶符號和無符號的運(yùn)算都是一樣的,而對于負(fù)數(shù)來說則是天壤之別。例如:-1>>>1=2147483647,數(shù)字很恐怖是吧,看看計算過程:-1的二進(jìn)制編碼為1111 1111 1111 1111 1111 1111 1111 1111,將其右移1位,并補(bǔ)0,得到0111 1111 1111 1111 1111 1111 1111 1111,第一位為0,是正數(shù),將其轉(zhuǎn)化為十進(jìn)制就是230+229+……+20=230(1-1/231)/(1-1/2)=231-1=2147483647,這樣最終得到了我們需要的結(jié)果,結(jié)果很恐怖,慎用!
位運(yùn)算符的應(yīng)用:
談了這么久,最終的目的還是為了去用這些運(yùn)算符,看些例子:
顏色的RGB值和十六進(jìn)制的轉(zhuǎn)換:例如一個顏色值:#33cc10,前兩位代表紅色(R),中間兩位代表綠色(G),后兩位代表藍(lán)色(B),將其轉(zhuǎn)化為二進(jìn)制編碼為:0011 0011 1100 1100 0001 0000(賦給color),首先我們要獲取紅色值,需要將其右移16位,color>>16,也就是0000 0000 0000 0000 0011 0011,這樣子我們獲取到R=51,那么我們要獲取綠色值就需要將其先右移8位,color>>8,得到0000 0000 0011 0011 1100 1100,然后將前八位變?yōu)?,0000 0000 0011 0011 1100 1100|0000 0000 0000 0000 1111 1111,得到0000 0000 0000 0000 1100 1100,這樣子我們得到G=204,最后取藍(lán)色值,就是簡單的將其前八位變?yōu)?,color | 0000 0000 0000 0000 0001 0000,我們得到B=16,#33cc10轉(zhuǎn)化為RGB值就是(51,204,16)。反過來RGB轉(zhuǎn)化為十六進(jìn)制正好是反過來的方法,就是G << 16 | G << 8 | B,這里就不贅述啦。
判斷一個節(jié)點是否為另一個節(jié)點的父節(jié)點:比如有兩個節(jié)點a和b,ie的方法是a.contains(b)來確定a是否為b的子節(jié)點,而其它現(xiàn)代瀏覽器使用的方法是a.compareDocumentPosition(b),這個返回結(jié)果并不是一個boolean值,如果a和b是同一個節(jié)點則返回0,a和b在不同的document內(nèi)或者至少有一個在document之外則返回1,如果b在a之前則返回2,a在b之前則返回4,b包含a則返回8,a包含b則返回16,32則為瀏覽器獨享。0、1、2、4、8、16的二進(jìn)制編碼分別為0000 0000、0000 0001、0000 0010、0000 0100、0000 1000、0001 0000,我們可以通過判斷a.compareDocumentPosition(b) & 16轉(zhuǎn)化為boolean是true還是false來判斷a是否為b的節(jié)點,那么為什么不用a.compareDocumentPosition(b) == 16判斷呢?因為a.compareDocumentPosition(b)返回的應(yīng)該是20(4+ 16),所以倒可以用a.compareDocumentPosition(b) == 20來運(yùn)算,用&運(yùn)算符的好處在于我們不需要考慮這些,我們只需要考慮它和我們需要的值16的&運(yùn)算是否可以返回true。(John Resig有一個模擬compareDocumentPosition的方法,讓其在ie下同樣適用,有興趣的可以參考文末的鏈接~)
按位左移運(yùn)算:我們知道按位左移1位,就是乘以2,那么我們可以用a<<1來代替a*2,因為位運(yùn)算的效率要快于普通運(yùn)算(有時候可能會得到相反的結(jié)果,JavaScript 中位運(yùn)算的速度非常的差,跟 C# 差的太遠(yuǎn)啦~)。
按位右移:一方面,可以用a>>1替代a/2,另外按位右移可以方便的將小數(shù)轉(zhuǎn)化為整數(shù),如3.1415>>0=3,因為按位移運(yùn)算會將運(yùn)算數(shù)必須為整型(詳細(xì)請參考 ECMA-262 手冊),所以操作后將舍棄小數(shù)位~
注:位運(yùn)算符要求它的數(shù)字運(yùn)算數(shù)是整型的,并且這些運(yùn)算數(shù)是用32位的整數(shù)來表示的,第32位是符號位。而且運(yùn)算數(shù)限制在32位的整數(shù)范圍內(nèi),同時要求右邊的運(yùn)算數(shù)在0到31之間。(本文二進(jìn)制編碼并不規(guī)范,僅為方便使用~)
相關(guān)文章:
