js >>> 0 談?wù)?js 中的位運算

晚上在讀 lodash 源碼的時候虱而,看到 baseSlice 中有這樣一行代碼:
start >>>= 0;

這不就是無符號右移嘛,當時第一感覺是是為了取絕對值,后來發(fā)現(xiàn)并不是漱受,嘗試了多次之后伶唯,發(fā)現(xiàn)情況有點詭異啊,我們使用 chrome 調(diào)試工具運行一下 js 中的無符號右移 0 位世杀。

chrome console

不僅是 null 無符號右移會變成 0 阀参,js 中的其他非數(shù)值做此運算都會變成 0 。

chrome console

接下來我們來看看為什么會這樣(事實上不僅僅只是無符號右移是這樣)瞻坝。要理解這個問題需要先明白什么是位運算以及為什么需要位運算蛛壳,然后搞明白 js 中的位運算有什么特別之處。

什么是位運算?

敬請期待

js 中的位運算有什么特別之處呢炕吸?

(這一部分我是拿 java伐憾、go 與 js 做對比的。)

1 js 中為什么浮點數(shù)也能參與位運算

這在 java赫模、go树肃、c 中都是不被允許的

* 6 種 基本類型:
    1. Boolean
    2. Null
    3. Undefined
    4. Number
    5. String
    6. Symbol (ECMAScript 6 新定義)

細心的人已經(jīng)發(fā)現(xiàn),基本類型里并沒有浮點型瀑罗。

事實上在 js 中的 Number 類型是不區(qū)分 int胸嘴、long、float斩祭、double 類型的(go 的用戶們就呵呵一笑了劣像,來來來,我們的浮點型就能王炸你)摧玫《龋回正題,不區(qū)分整型诬像、浮點型那怎么存儲呢屋群,為了不丟失精度, js 中的 Number 類型實際上一個基于 IEEE 754 標準的雙精度64位浮點數(shù)(java 的同學(xué)就把它當成 double 看)坏挠∩瞩铮看到這我想很多人應(yīng)該能明白為什么 js 里浮點數(shù)也能參與位運算了吧。這也是沒有辦法降狠,因為對于內(nèi)存來說整型对竣、浮點型都沒有區(qū)別了。

這里是有一個問題的榜配,因為當 js 需要進行位運算時否纬,會將操作數(shù)通通轉(zhuǎn)成 32 位比特序列(0,1)芥牌,也就是補碼烦味。操作完成之后,再按照 64 位浮點數(shù)存儲

2 那么 js 做位運算時壁拉,小數(shù)部分怎么處理呢?

注意這里說的全部位運算

直接丟棄0匕小F怼! 曾吶屎蜓!這么虎痘昌?

沒錯,就是這么暴力,那么問題來了辆苔,既然小數(shù)部分不參與位運算算灸,那么為什么不能像 java、go 那樣直接禁止呢驻啤?關(guān)于這個問題菲驴,我想那就是語言設(shè)計者的想法,我就不知道了骑冗。但是這其實也帶來了一些特別的操作赊瞬,比如在 js 中雙取反是可以做取整操作的。

~~2.2 // 2
~~2.8 // 2

3 js 中非數(shù)值類型如何進行位運算的呢贼涩?

js 需要進行位運算的時候巧涧,對于非數(shù)值類型,會首先將操作數(shù)轉(zhuǎn)成一個整型(就是0)然后在進行運算遥倦。這就解釋了為什么 js 中可以允許非數(shù)值類型參與運算谤绳,其實這是個偽命題,因為實質(zhì)上是對非數(shù)值操作數(shù)的整型表達式進行的位運算袒哥。

這里需要注意闷供,上面說過了 js 中的整型在內(nèi)存中都是一個 64 位雙精度浮點型,但是 js 進行位運算時统诺,會將操作數(shù)轉(zhuǎn)成帶符號位的 32 位比特序列(0歪脏,1),也就是補碼粮呢。運算結(jié)束后婿失,再按照 64 位存儲。那么問題來了啄寡,這里肯定會存在精度丟失對吧豪硅,這應(yīng)該不難理解。js 確實也是這樣處理的挺物,超過 32 位的部分直接截斷懒浮。

所以對一個非數(shù)值變量做取反操作,得到的一定是 -1识藤,因為實際上等于對 0 做取反操作砚著。

chrome console

4 js 中的無符號右移到底有什么特別之處?

首尾呼應(yīng)一下痴昧,畢竟就是這個問題使我查資料寫了這篇文章稽穆。

首先解釋一下,>>> 無符號右移原本是 java 里特有的(這里是和 js赶撰、go 對比舌镶,其他語言我沒用過柱彻,不能亂說)。js 中的無符號右移跟 java 幾乎一樣餐胀,除了一點兩種語言處理方式完全不一樣哟楷。

那就是并沒有真正發(fā)生移位的情況下,符號位會不會被替換成0否灾。java 中是不會替換的卖擅,但是 js 中是會發(fā)生替換的。

當操作數(shù)是正數(shù)的時候坟冲,不管有沒有真的移位并沒有區(qū)別磨镶,因為正數(shù)的符號位是 0。
當操作數(shù)是負數(shù)時健提,移動位數(shù)大于0琳猫,也體現(xiàn)不出區(qū)別:

// java
5 >>> 0  // 5
5 >>> 1  // 2
-1 >>> 1 // 2147483647

// js
5 >>> 0  // 5
5 >>> 1  // 2
-1 >>> 1 // 2147483647

但是當操作數(shù)是負數(shù),無符號右移 0 位時私痹,區(qū)別就大了:

// java
-1 >>> 0 // -1

// js
-1 >>> 0 // 4294967295

這是因為 -1 的補碼是:

11111111111111111111111111111111

>>>0 實際上并沒有發(fā)生數(shù)位變化脐嫂,但是 js 卻會把符號位替換成 0,

// java
11111111111111111111111111111111

// js
01111111111111111111111111111111

此時原來負數(shù)的補碼紊遵,變?yōu)榱苏龜?shù)的源碼(這就是為什么 js 中 -1>>>0 會變成一個巨大的正整數(shù))账千。

js 中無符號右移時,不管正數(shù)暗膜、負數(shù)都會首先將符號位替換成 0匀奏,然后再進行移位。也就是說学搜,該運算符永遠返回正整數(shù)娃善。

總結(jié)

js 的位運算,為什么會有這么多奇怪的地方呢瑞佩?我相信很多同學(xué)都會有這種想法聚磺,特別是 java 的同學(xué)們吧。為此我查了 js 的歷史炬丸。

1995 Sun 公司正式發(fā)布 java 語言瘫寝,當時的網(wǎng)景公司正在為它們的 Navigator 瀏覽器尋找一種網(wǎng)頁腳本(此前的瀏覽器不具備互動能力)。當他們看到 Sun 公司的宣傳后稠炬,與 Sun 合作開發(fā)全新的腳本語言 javascript 焕阿。此前我一直不明白 js 既然不是 java 的腳本,為什么叫這個名字∷岣伲現(xiàn)在懂了捣鲸,因為當時新腳本語言的決策中,Sun 公司占了很大一環(huán)闽坡。

1995年5月 按照公司的要求(一個像 java 但是比 java 簡單的腳本語言)栽惶,Brendan Eich 僅用10天就寫出了 javascript

在我們膜拜大神的時候疾嗅,也要認清一個現(xiàn)實外厂,當時給 Brendan Eich 的時間太短了,所以很多問題并沒有很好的解決代承,而且一邊模仿 java汁蝶、c,一邊還要簡化數(shù)據(jù)類型论悴、內(nèi)存模型掖棉。我覺得這就是為什么 js 的位運算這么奇怪的原因。

js 完全套用了 java 的位運算符膀估。
但是 java 的位運算是針對整數(shù)的幔亥,對 js 沒什么用啊,因為 js 中察纯,所有數(shù)字都保存為雙精度浮點型帕棉。如果使用它們的話,js 不得不將操作數(shù)先轉(zhuǎn)為整數(shù)饼记,然后再進行運算香伴。

所以很多人不建議在 js 中使用位運算,理由是 js 天生就會進行類型轉(zhuǎn)換具则,使得效率降低即纲。

到底在項目中要不要用位運算,我覺得效率啦博肋、存儲空間啦都不是問題低斋,重要的是可讀性,如果你的團隊成員都比較擅長位運算束昵,那就可以用(其實很多時候位運算更方便業(yè)務(wù)的實現(xiàn)跟理解拔稳,比如開關(guān)量,可以用與或非很快的表達出一些復(fù)雜的邏輯判斷)锹雏。反過來巴比,如果大家連二進制存儲都整不明白,那就不要用礁遵,不然以后沒人懂你寫了什么轻绞。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市佣耐,隨后出現(xiàn)的幾起案子政勃,更是在濱河造成了極大的恐慌,老刑警劉巖兼砖,帶你破解...
    沈念sama閱讀 221,198評論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件奸远,死亡現(xiàn)場離奇詭異既棺,居然都是意外死亡,警方通過查閱死者的電腦和手機懒叛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評論 3 398
  • 文/潘曉璐 我一進店門丸冕,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人薛窥,你說我怎么就攤上這事胖烛。” “怎么了诅迷?”我有些...
    開封第一講書人閱讀 167,643評論 0 360
  • 文/不壞的土叔 我叫張陵佩番,是天一觀的道長。 經(jīng)常有香客問我罢杉,道長趟畏,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,495評論 1 296
  • 正文 為了忘掉前任屑那,我火速辦了婚禮拱镐,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘持际。我一直安慰自己沃琅,他們只是感情好,可當我...
    茶點故事閱讀 68,502評論 6 397
  • 文/花漫 我一把揭開白布蜘欲。 她就那樣靜靜地躺著益眉,像睡著了一般。 火紅的嫁衣襯著肌膚如雪姥份。 梳的紋絲不亂的頭發(fā)上郭脂,一...
    開封第一講書人閱讀 52,156評論 1 308
  • 那天,我揣著相機與錄音澈歉,去河邊找鬼展鸡。 笑死,一個胖子當著我的面吹牛埃难,可吹牛的內(nèi)容都是我干的莹弊。 我是一名探鬼主播,決...
    沈念sama閱讀 40,743評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼涡尘,長吁一口氣:“原來是場噩夢啊……” “哼忍弛!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起考抄,我...
    開封第一講書人閱讀 39,659評論 0 276
  • 序言:老撾萬榮一對情侶失蹤细疚,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后川梅,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體疯兼,經(jīng)...
    沈念sama閱讀 46,200評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡然遏,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,282評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了镇防。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片啦鸣。...
    茶點故事閱讀 40,424評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡潮饱,死狀恐怖来氧,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情香拉,我是刑警寧澤啦扬,帶...
    沈念sama閱讀 36,107評論 5 349
  • 正文 年R本政府宣布,位于F島的核電站凫碌,受9級特大地震影響扑毡,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜盛险,卻給世界環(huán)境...
    茶點故事閱讀 41,789評論 3 333
  • 文/蒙蒙 一瞄摊、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧苦掘,春花似錦换帜、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至递瑰,卻和暖如春祟牲,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背抖部。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評論 1 271
  • 我被黑心中介騙來泰國打工说贝, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人慎颗。 一個月前我還...
    沈念sama閱讀 48,798評論 3 376
  • 正文 我出身青樓乡恕,卻偏偏與公主長得像,于是被迫代替她去往敵國和親哗总。 傳聞我的和親對象是個殘疾皇子几颜,可洞房花燭夜當晚...
    茶點故事閱讀 45,435評論 2 359

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

  • 第2章 基本語法 2.1 概述 基本句法和變量 語句 JavaScript程序的執(zhí)行單位為行(line),也就是一...
    悟名先生閱讀 4,151評論 0 13
  • 一讯屈、ECMAScript 一元運算符 一元運算符只有一個參數(shù)蛋哭,即要操作的對象或值。它們是 ECMAScript 中...
    耦耦閱讀 535評論 0 0
  • 我們一路撕心吶喊涮母,搖滾落寞谆趾,吧嗒一聲躁愿,子彈還在飛,人已到中年沪蓬。 要命的是這種察覺很唐突彤钟,就像是...
    水煮蓮花閱讀 716評論 6 14