JavaScript中奇特的~運算符

寫在最前

本次分享一下并不是很常用的按位非運算符~的原理以及一點點用法。


歡迎關注我的博客,不定期更新中——

JavaScript小眾系列開始更新啦

——何時完結不確定,寫多少看我會多少!這是已經更新的地址:

這個系列旨在對一些人們不常用遇到的知識點,以及可能常用到但不曾深入了解的部分做一個重新梳理,雖然可能有些部分看起來沒有什么用,因為平時開發真的用不到!但個人認為糟粕也好精華也罷里面全部蘊藏著JS一些偏本質的東西或者說底層規范,如果能適當避開舒適區來看這些小細節,也許對自己也會有些幫助~文章更新在我的博客,歡迎不定期關注。

~的規則是什么

看下規范里面的定義的~:

產生式 UnaryExpression : ~ UnaryExpression 按照下面的過程執行:

  1. 令 expr 為解釋執行 UnaryExpression 的結果。

  2. 令 oldValue 為 ToInt32(GetValue(expr))。

  3. 返回 oldValue 按位取反的結果。結果為 32位 有符號整數。

總結一下即將數字進行抽象Toint32操作,再進行按位取反。那么再來看下關于Toint32:


image

數字進行Toint32操作會轉化成32位有符號數,第一位為符號位,后面31位為表示整數數值。最后對數字進行按位取反即可得到~轉換后的結果。

舉個??

//以18為例子,進行Toint32抽象操作
//將18表示為二進制形式
     0    000 0000 0000 0000 0000 0000 0001 0010
//|符號位||              數值部分                |  

//按位取反
    1     111 1111 1111 1111 1111 1111 1110 1101
//|符號位||              數值部分                |  

可以發現現在將18進行了按位非操作之后這個數變成了一個負數,同時我們可以看到這么多個1。。感覺這個負數很大啊?所以~18會是一個很大的負數么?我們打印看下:

image

好像和預料中的有些出入?

負數是如何存成二進制的?

我們可以直接打印看下:

image

然而這并不是我們想要的,會有這個結果是因為ECMAScript采用了這樣簡單的方式來避免開發者接觸一些底層的操作,真實的存儲二進制負數的方式應該是采用補碼的形式。而也正是由于補碼的操作我們才能解釋為什么~18 === -19

補碼

生成補碼的三個步驟:

確定該數字的非負版本的二進制表示(例如,要計算 -18的二進制補碼,首先要確定 18 的二進制表示)

求得二進制反碼,即要把 0 替換為 1,把 1 替換為 0

在二進制反碼上加 1

我們先不管為什么負數要用補碼來存儲,先來看下~18 === -19是如何而來的。
根據上述計算-19的補碼步驟:

//將19表示為二進制形式
     0    000 0000 0000 0000 0000 0000 0001 0011
//|符號位||              數值部分                |  

//按位取反
    1     111 1111 1111 1111 1111 1111 1110 1100
//|符號位||              數值部分                |  

//反碼加一
    1     111 1111 1111 1111 1111 1111 1110 1100
                                               1
    --------------------------------------------
    1     111 1111 1111 1111 1111 1111 1110 1101
//同時 18的按位取反表示為:
    1     111 1111 1111 1111 1111 1111 1110 1101

所以我們可以看到,由于補碼為按位取反并+1,~ 為按位取反,那么也就可以說明為什么~18 === -19 同時我們也可以得出結論即:

~x === -(x+1)

那么為什么負數存儲為補碼?

因為計算機在做二進制運算的時候,不希望考慮運算數的符號,全部希望執行加法操作來得出正確結果,由此引入了補碼的概念。比如我們試圖用4-2的結果與4+2的補碼結果比對來進行說明:

4 - 2 =>
0100 - 0010 = 0010
4 + (-2) =>
0010 + 1110 = 0010(相加超過位數,溢出自動丟失)

~的應用

對哨位值進行~操作

哨位值一般可以表示失敗的意思。例如js中的哨位值如-1,當你執行indexOf操作時,如果找不到目標則返回-1,同時~-1 = 0,由此我們可以將代碼轉變為:

if(str.indexOf('js') != -1) => if(~indexOf('js'))

那么為什么不使用>=0或者!= -1這種操作呢,在《你不知道的JavaScript》一書中,將之成為“抽象滲漏”,意思是在代碼中暴露了底層實現細節,我們可以選擇屏蔽掉細節。故 ~ 可以和indexOf進行配合判斷真假值,核心思路就是運用了~x === -(x+1)

浮點數取整

我們現在知道~ 會進行按位取反的過程中會進行Toint32抽象操作,在這個過程中會將浮點數去掉,只對前面32位整數進行處理。故我們可以使用~進行以下操作:

~~3.12 = 3

同時需要注意由于~的特性,小數點后面的部分是直接被干掉的,而不是會進行Math.floor之類的四舍五入操作。

參考資料

最后

慣例po作者的博客,不定時更新中——
有問題歡迎在issues下交流。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 網站亂碼問題我們會經常碰到,大多見于非英文的中文字符或其他字符亂碼,而且,這類問題常常是因為編碼方式問題,主要原因...
    波段頂底閱讀 2,961評論 1 9
  • 高級運算符(Advanced Operators) 本文參考自蘋果官方文檔Advanced Operators本頁...
    果啤閱讀 1,615評論 1 5
  • 神都來 云游方 尋天女 覓知己 求長生 修仙術 吞秘藏 吃山珍 一個人 獨自行 南也走 北亦闖 哭了嗎 笑了吧 懷...
    詩凡逸臣閱讀 223評論 0 0
  • 當蜘蛛網無情地查封了我的爐臺 當灰燼的余煙嘆息著貧困的悲哀 我依然固執地鋪平失望的灰燼 用美麗的雪花寫下:相信未來...
    Super菁閱讀 245評論 0 0
  • 青海是個讓人忘卻煩惱的地方,湖水和天空都純凈的讓人駐足。 或許我曾經來過,誠然我還會再來
    我想我該想想閱讀 247評論 0 1