成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

為什么不要在 JavaScript 中使用位操作符?

eternalshallow / 459人閱讀

摘要:但事實(shí)上,位操作符并不是這么認(rèn)為的。再者,在中使用位操作符的地方畢竟太少,如果你執(zhí)意使用位操作符,未來維護(hù)這段代碼的人又對中的位操作符的坑不熟悉,這也會造成不利的影響。所以,我對大家的建議是,盡量在中別使用位操作符。

  

本文最早在我的個人博客《咀嚼之味》發(fā)布:http://jerryzou.com

如果你的第一門編程語言不是 JavaScript,而是 C++ 或 Java,那么一開始你大概會看不慣 JavaScript 的數(shù)字類型。在 JavaScript 中的數(shù)字類型是不區(qū)分什么 Int,F(xiàn)loat,Double,Decimal 的??瓤?,我說的當(dāng)然是在 ES6 之前的 JS,在 ES6 的新標(biāo)準(zhǔn)中提出了像 Int8Array 這樣新的數(shù)據(jù)類型。不過這不是本文敘述的重點(diǎn),暫且就不談啦。本文將更著重地談 JS 的數(shù)字類型以及作用于它的位操作符,而關(guān)于包裝對象 Number 的更多了解可以看拔赤翻譯的《JavaScript設(shè)計模式》

數(shù)字類型的本質(zhì)

實(shí)際上,JavaScript的數(shù)字類型的本質(zhì)就是一個基于 IEEE 754 標(biāo)準(zhǔn)的雙精度 64 位的浮點(diǎn)數(shù)。按照標(biāo)準(zhǔn),它的數(shù)據(jù)結(jié)構(gòu)如圖示這樣:由1位符號位,11位指數(shù)部分以及52位尾數(shù)部分構(gòu)成。

在浮點(diǎn)數(shù)中,數(shù)字通常被表示為:

(-1)sign × mantissa × 2exponent

而為了將尾數(shù)規(guī)格化,并做到盡量提高精確度,就需要把尾數(shù)精確在 [1,2) 的區(qū)間內(nèi),這樣便可省去前導(dǎo)的1。比如:

11.101 × 23 = 1.1101 × 24
0.1001 × 25 = 1.001 × 24

并且標(biāo)準(zhǔn)規(guī)定指數(shù)部分使用 0x3ff 作為偏移量,也就有了雙精度浮點(diǎn)數(shù)的一般公式:

(-1)sign × 1.mantissa × 2exponent - 0x3ff

舉一些例子,應(yīng)該能幫助你理解這個公式:

3ff0 0000 0000 0000  =  1
c000 0000 0000 0000  =  -2
3fd5 5555 5555 5555  ~  1/3
0000 0000 0000 0000  =  0
8000 0000 0000 0000  =  -0
7ff0 0000 0000 0000  =  無窮大 ( 1/0 )
fff0 0000 0000 0000  =  負(fù)無窮大 ( 1/-0 )
7fef ffff ffff ffff  ~  1.7976931348623157 x 10^308 (= Number.MAX_VALUE)
433f ffff ffff ffff  =  2^53 - 1 (= Number.MAX_SAFE_INTEGER)
c33f ffff ffff ffff  =  -2^53 + 1 (= Number.MIN_SAFE_INTEGER)

得益于尾數(shù)省略的一位“1”,使用雙精度浮點(diǎn)數(shù)來表示的最大安全整數(shù)為 -253+1 到 253-1 之間,所以如果你僅僅使用 JavaScript 中的數(shù)字類型進(jìn)行一些整數(shù)運(yùn)算,那么你也可以近似地將這一數(shù)字類型理解為 53 位整型。

讓人又愛又恨的位操作符

熟悉 C 或者 C++ 的同學(xué)一定對位操作符不陌生。位操作符最主要的應(yīng)用大概就是作為標(biāo)志位與掩碼。這是一種節(jié)省存儲空間的高明手段,在曾經(jīng)內(nèi)存的大小以 KB 為單位計算時,每多一個變量就是一份額外的開銷。而使用位操作符的掩碼則在很大程度上緩解了這個問題:

#define LOG_ERRORS            1  // 0001
#define LOG_WARNINGS          2  // 0010
#define LOG_NOTICES           4  // 0100
#define LOG_INCOMING          8  // 1000

unsigned char flags;

flags = LOG_ERRORS;                                 // 0001
flags = LOG_ERRORS | LOG_WARNINGS | LOG_INCOMING;   // 1011

因?yàn)闃?biāo)志位一般只需要 1 bit,就可以保存,并沒有必要為每個標(biāo)志位都定義一個變量。所以按上面這種方式只使用一個變量,卻可以保存大量的信息——無符號的 char 可以保存 8 個標(biāo)志位,而無符號的 int 則可以同時表示 32 個標(biāo)志位。

可惜位操作符在 JavaScript 中的表現(xiàn)就比較詭異了,因?yàn)?JavaScript 沒有真正意義上的整型??纯慈缦麓a的運(yùn)行結(jié)果吧:

var a, b;

a = 2e9;   // 2000000000
a << 1;    // -294967296

// fxck!我只想裝了個逼用左移1位給 a * 2,但是結(jié)果是什么鬼?。?!

a = parseInt("100000000", 16); // 4294967296
b = parseInt("1111", 2);       // 15
a | b;                         // 15

// 啊啊啊,為毛我的 a 絲毫不起作用,JavaScript真是門吊詭的語言?。?!

好吧,雖然我說過大家可以近似地認(rèn)為,JS 的數(shù)字類型可以表示 53 位的整型。但事實(shí)上,位操作符并不是這么認(rèn)為的。在 ECMAScript? Language Specification 中是這樣描述位操作符的:

  

The production A : A @ B, where @ is one of the bitwise operators in the productions above, is evaluated as follows:

Let lref be the result of evaluating A.

Let lval be GetValue(lref).

Let rref be the result of evaluating B.

Let rval be GetValue(rref).

Let lnum be ToInt32(lval).

Let rnum be ToInt32(rval).

Return the result of applying the bitwise operator @ to lnum and rnum. The result is a signed 32 bit integer.

需要注意的是第5和第6步,按照ES標(biāo)準(zhǔn),兩個需要運(yùn)算的值會被先轉(zhuǎn)為有符號的32位整型。所以超過32位的整數(shù)會被截斷,而小數(shù)部分則會被直接舍棄。

而反過來考慮,我們在什么情況下需要用到位操作符?使用左移來代替 2 的冪的乘法?Naive啊,等遇到像第一個例子的問題,你就要抓狂了。而且對一個浮點(diǎn)數(shù)進(jìn)行左移操作是否比直接乘 2 來得效率高,這也是個值得商榷的問題。

那用來表示標(biāo)志位呢?首先,現(xiàn)在的內(nèi)存大小已經(jīng)不值得我們用精簡幾個變量來減少存儲空間了;其次呢,使用標(biāo)志位也會使得代碼的可讀性大大下降。再者,在 JavaScript 中使用位操作符的地方畢竟太少,如果你執(zhí)意使用位操作符,未來維護(hù)這段代碼的人又對 JS 中的位操作符的坑不熟悉,這也會造成不利的影響。

所以,我對大家的建議是,盡量在 JavaScript 中別使用位操作符。

參考資料

維基百科:雙精度浮點(diǎn)數(shù)

MDN:JavaScript數(shù)據(jù)結(jié)構(gòu)

MDN:按位操作符

How to use bitmask?

ECMAScript? Language Specification - 11.10 Binary Bitwise Operators

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/85708.html

相關(guān)文章

  • JavaScript的“黑話”

    摘要:數(shù)值表示法科學(xué)計數(shù)法是一種數(shù)學(xué)術(shù)語,將一個數(shù)表示為乘以的次方,如光速萬公里每秒,在計算中通常將米做單位,則記為,而在中我們可使用科學(xué)計數(shù)法表示。以下情況會自動將數(shù)值轉(zhuǎn)為科學(xué)計數(shù)法表示小數(shù)點(diǎn)前的數(shù)字多于位。 showImg(https://segmentfault.com/img/bVbhNqT?w=1024&h=683); 因?yàn)榍蚴菆A的,所以不論發(fā)生什么都有可能,對這點(diǎn)我是深信不疑的,...

    fjcgreat 評論0 收藏0
  • JavaScript 性能優(yōu)化

    摘要:如果你忽略這兩個步驟,那么在第二步所產(chǎn)生的任何修改都會觸發(fā)一次重排。 更多文章 加載與執(zhí)行 將標(biāo)簽放在前面,不要放在中,防止造成堵塞 盡量減少請求,單個100KB的文件比4個25KB的文件更快,也就是說減少頁面中外鏈的文件會改善性能 盡量使用壓縮過的JS文件,體積更小,加載更快 數(shù)據(jù)存取 使用局部變量和字面量比使用數(shù)組和對象有更少的讀寫消耗 盡可能使用局部變量代替全局變量 如無必...

    ad6623 評論0 收藏0
  • 高程3總結(jié)#第24章最佳實(shí)踐

    摘要:也就是說避免屬性查找或其他的操作。簡化循環(huán)體循環(huán)體是執(zhí)行最多的,所以要確保其被最大限度地優(yōu)化。代碼組織組織代碼要考慮到可維護(hù)性并不一定是傳送給瀏覽器的最好方式。 最佳實(shí)踐 可維護(hù)性 什么是可維護(hù)性的代碼 如果說代碼是可維護(hù)的,它需要遵循以下特點(diǎn) 可理解性——其他人可以接手代碼并理解它的意圖和一般途徑,而無需原開發(fā)人員的完整解釋。 直觀性——代碼中的東西一看就能明白,不管其操作過程多...

    zhiwei 評論0 收藏0
  • JavaScript作符的特殊作用

    摘要:主要有以下幾種位操作符一般來說,我們在中很少能用到這些位操作符,但在某些特殊情況下,這些簡單的操作符卻能抵得上好幾行代碼如果不在乎可讀性的話。 Javascript主要有以下幾種位操作符: AND ( & ) OR ( | ) XOR ( ^ ) NOT ( ~ ) LEFT SHIFT ( ) ZERO-FILL RIGHT SHIFT ( >>> ) 一般來說,我們在Java...

    NeverSayNever 評論0 收藏0
  • JavaScript是怎樣編碼數(shù)字的[How numbers are encoded in Java

    摘要:譯者注規(guī)范化就是把小數(shù)點(diǎn)放在第一個非零數(shù)字的后面總結(jié)當(dāng)指數(shù)的范圍是十進(jìn)制分?jǐn)?shù)不是所有的十進(jìn)制分?jǐn)?shù)都能夠非常精確的表示例如和都不能夠被精確的表示成二進(jìn)制浮點(diǎn)數(shù)。相同的,也不能被精確表示成一個十進(jìn)制分?jǐn)?shù),它大概能被表示成。 在JavaScript中所有的數(shù)字都是浮點(diǎn)數(shù),本篇文章將介紹這些浮點(diǎn)數(shù)在JavaScript內(nèi)部是怎樣被轉(zhuǎn)為64位二進(jìn)制的。我們會特別考慮整數(shù)的處理,所以讀完本篇之后,...

    oysun 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<