摘要:但事實上,位操作符并不是這么認為的。再者,在中使用位操作符的地方畢竟太少,如果你執意使用位操作符,未來維護這段代碼的人又對中的位操作符的坑不熟悉,這也會造成不利的影響。所以,我對大家的建議是,盡量在中別使用位操作符。
本文最早在我的個人博客《咀嚼之味》發布:http://jerryzou.com
如果你的第一門編程語言不是 JavaScript,而是 C++ 或 Java,那么一開始你大概會看不慣 JavaScript 的數字類型。在 JavaScript 中的數字類型是不區分什么 Int,Float,Double,Decimal 的。咳咳,我說的當然是在 ES6 之前的 JS,在 ES6 的新標準中提出了像 Int8Array 這樣新的數據類型。不過這不是本文敘述的重點,暫且就不談啦。本文將更著重地談 JS 的數字類型以及作用于它的位操作符,而關于包裝對象 Number 的更多了解可以看拔赤翻譯的《JavaScript設計模式》
數字類型的本質實際上,JavaScript的數字類型的本質就是一個基于 IEEE 754 標準的雙精度 64 位的浮點數。按照標準,它的數據結構如圖示這樣:由1位符號位,11位指數部分以及52位尾數部分構成。
在浮點數中,數字通常被表示為:
(-1)sign × mantissa × 2exponent
而為了將尾數規格化,并做到盡量提高精確度,就需要把尾數精確在 [1,2) 的區間內,這樣便可省去前導的1。比如:
11.101 × 23 = 1.1101 × 24
0.1001 × 25 = 1.001 × 24
并且標準規定指數部分使用 0x3ff 作為偏移量,也就有了雙精度浮點數的一般公式:
(-1)sign × 1.mantissa × 2exponent - 0x3ff
舉一些例子,應該能幫助你理解這個公式:
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 = 負無窮大 ( 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)
得益于尾數省略的一位“1”,使用雙精度浮點數來表示的最大安全整數為 -253+1 到 253-1 之間,所以如果你僅僅使用 JavaScript 中的數字類型進行一些整數運算,那么你也可以近似地將這一數字類型理解為 53 位整型。
讓人又愛又恨的位操作符熟悉 C 或者 C++ 的同學一定對位操作符不陌生。位操作符最主要的應用大概就是作為標志位與掩碼。這是一種節省存儲空間的高明手段,在曾經內存的大小以 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
因為標志位一般只需要 1 bit,就可以保存,并沒有必要為每個標志位都定義一個變量。所以按上面這種方式只使用一個變量,卻可以保存大量的信息——無符號的 char 可以保存 8 個標志位,而無符號的 int 則可以同時表示 32 個標志位。
可惜位操作符在 JavaScript 中的表現就比較詭異了,因為 JavaScript 沒有真正意義上的整型。看看如下代碼的運行結果吧:
var a, b; a = 2e9; // 2000000000 a << 1; // -294967296 // fxck!我只想裝了個逼用左移1位給 a * 2,但是結果是什么鬼!!! a = parseInt("100000000", 16); // 4294967296 b = parseInt("1111", 2); // 15 a | b; // 15 // 啊啊啊,為毛我的 a 絲毫不起作用,JavaScript真是門吊詭的語言!!!
好吧,雖然我說過大家可以近似地認為,JS 的數字類型可以表示 53 位的整型。但事實上,位操作符并不是這么認為的。在 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標準,兩個需要運算的值會被先轉為有符號的32位整型。所以超過32位的整數會被截斷,而小數部分則會被直接舍棄。
而反過來考慮,我們在什么情況下需要用到位操作符?使用左移來代替 2 的冪的乘法?Naive啊,等遇到像第一個例子的問題,你就要抓狂了。而且對一個浮點數進行左移操作是否比直接乘 2 來得效率高,這也是個值得商榷的問題。
那用來表示標志位呢?首先,現在的內存大小已經不值得我們用精簡幾個變量來減少存儲空間了;其次呢,使用標志位也會使得代碼的可讀性大大下降。再者,在 JavaScript 中使用位操作符的地方畢竟太少,如果你執意使用位操作符,未來維護這段代碼的人又對 JS 中的位操作符的坑不熟悉,這也會造成不利的影響。
所以,我對大家的建議是,盡量在 JavaScript 中別使用位操作符。
參考資料維基百科:雙精度浮點數
MDN:JavaScript數據結構
MDN:按位操作符
How to use bitmask?
ECMAScript? Language Specification - 11.10 Binary Bitwise Operators
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/85708.html
摘要:數值表示法科學計數法是一種數學術語,將一個數表示為乘以的次方,如光速萬公里每秒,在計算中通常將米做單位,則記為,而在中我們可使用科學計數法表示。以下情況會自動將數值轉為科學計數法表示小數點前的數字多于位。 showImg(https://segmentfault.com/img/bVbhNqT?w=1024&h=683); 因為球是圓的,所以不論發生什么都有可能,對這點我是深信不疑的,...
摘要:如果你忽略這兩個步驟,那么在第二步所產生的任何修改都會觸發一次重排。 更多文章 加載與執行 將標簽放在前面,不要放在中,防止造成堵塞 盡量減少請求,單個100KB的文件比4個25KB的文件更快,也就是說減少頁面中外鏈的文件會改善性能 盡量使用壓縮過的JS文件,體積更小,加載更快 數據存取 使用局部變量和字面量比使用數組和對象有更少的讀寫消耗 盡可能使用局部變量代替全局變量 如無必...
摘要:也就是說避免屬性查找或其他的操作。簡化循環體循環體是執行最多的,所以要確保其被最大限度地優化。代碼組織組織代碼要考慮到可維護性并不一定是傳送給瀏覽器的最好方式。 最佳實踐 可維護性 什么是可維護性的代碼 如果說代碼是可維護的,它需要遵循以下特點 可理解性——其他人可以接手代碼并理解它的意圖和一般途徑,而無需原開發人員的完整解釋。 直觀性——代碼中的東西一看就能明白,不管其操作過程多...
摘要:主要有以下幾種位操作符一般來說,我們在中很少能用到這些位操作符,但在某些特殊情況下,這些簡單的操作符卻能抵得上好幾行代碼如果不在乎可讀性的話。 Javascript主要有以下幾種位操作符: AND ( & ) OR ( | ) XOR ( ^ ) NOT ( ~ ) LEFT SHIFT ( ) ZERO-FILL RIGHT SHIFT ( >>> ) 一般來說,我們在Java...
摘要:譯者注規范化就是把小數點放在第一個非零數字的后面總結當指數的范圍是十進制分數不是所有的十進制分數都能夠非常精確的表示例如和都不能夠被精確的表示成二進制浮點數。相同的,也不能被精確表示成一個十進制分數,它大概能被表示成。 在JavaScript中所有的數字都是浮點數,本篇文章將介紹這些浮點數在JavaScript內部是怎樣被轉為64位二進制的。我們會特別考慮整數的處理,所以讀完本篇之后,...
閱讀 1438·2021-09-28 09:44
閱讀 2501·2021-09-28 09:36
閱讀 1144·2021-09-08 09:35
閱讀 1982·2019-08-29 13:50
閱讀 810·2019-08-29 13:29
閱讀 1130·2019-08-29 13:15
閱讀 1724·2019-08-29 13:00
閱讀 2988·2019-08-26 16:16