關(guān)于js中的`~~`和`!!`

國家地理

首頁圖來自看大圖剩瓶,侵刪延曙。



今天看到這樣一段代碼:

// JavaScript代碼
if ( !~items.indexOf( item ) ) {  
    items.push(item);  
}  

!~ 是什么最新操作亡哄?于是花了一些時間查找了相關(guān)資料學(xué)習(xí)了一下。

先上干貨蚊惯,結(jié)論如下:

事實上截型,這是兩個運算,第一個運算是!发钝,js中代表邏輯非;第二個運算是~酝豪,意義為按位非

上面那個例子蒲障,是在items這個數(shù)組中查找元素item的下標(biāo)瘫证,使用indexOf()函數(shù)背捌。

ps: 其實不僅在js中有這種語法,其他任何語言也都會有。

  • 如果在集合中查找到了item巡扇,則該函數(shù)返回對應(yīng)下標(biāo),是一個大于0的整數(shù),該整數(shù)按位非的結(jié)果一定不為0乖坠,取邏輯非后刀闷,表達式結(jié)果為假。
  • 如果在集合中沒找到item顽分,則該函數(shù)返回-1這個值卒蘸。而恰好翻默,-1這個值按位非的結(jié)果剛好是0,再取邏輯非后,表達式結(jié)果為真趾牧。

所以前面提到的代碼的含義為肯污,如果在items中沒有item這個元素吨枉,就添加到items中东羹。

有貓病吧属提?

可能有些人看到這里就怒了美尸!欺負我智商不夠嗎?這種簡單的功能恕酸,我分分鐘就能寫出來好嗎胯陋?走你:

// 方法1
if ( items.indexOf( item ) === -1) {  
    items.push(item);
}
// 方法2
if ( tems.indexOf( item ) < 0) {  
    items.push(item);  
}

扎心了,老鐵义矛,這三種方法實現(xiàn)的功能都是一樣的好嗎凉翻?那為什么還要使用這種晦澀難懂的語法呢捻激?我們可以揣摩一下這段代碼的作者的心里活動如下:

這種高級語法,其他人做得到嗎垃杖?韭赘??(叉會兒腰)

好吧脉漏,我們設(shè)想一下袖牙,也許是效率問題鞭达?這種語法更接近底層皇忿,所以執(zhí)行效率更快鳍烁?根據(jù)相關(guān)資料和測試繁扎,按位非的寫法似乎也并沒有明顯的效率提升,反而還不如平時我們寫的邏輯判斷爹梁。ps:此處存疑提澎。
所以,如果是日常使用的話积糯,不知道~是什么操作也完全OK絮宁。不想知道~是什么的話服协,閣下可以關(guān)掉這個頁面了偿荷。


什么是按位非~?

好吧唠椭,我們來剖析一下這里面的門道,看一下按位非操作是什么樣子的寺庄。在深入之前力崇,我們需要先回顧一下相關(guān)知識。

原碼馍盟、反碼贞岭、補碼

來復(fù)習(xí)一下計算機基礎(chǔ)八毯,數(shù)字在計算機中是以二進制的形式存在的话速,那具體的存放規(guī)則又是什么呢?此處我們立一個大前提泊交,假設(shè)我們所處的環(huán)境是8位機活合,并且先只考慮整數(shù)的情況物赶。具體來看一下:

數(shù)字4用二進制表示是100。由于是正數(shù)酵紫,首位字符位是0,所以補全位數(shù)是0000 0100橄唬,這個就是數(shù)字4的原碼仰楚。由于正數(shù)的原碼補碼反碼都相等,所以數(shù)字4的反碼和補碼也是0000 0100僧界。

如果是負數(shù)呢臭挽?比如數(shù)字-4欢峰,應(yīng)先取正數(shù)的原碼,即0000 0100宠漩,然后將首位(符號位)變?yōu)?,代表這是負數(shù)哄孤,所以我們得到了數(shù)字-4的原碼是1000 0100瘦陈。然后將除了首位(符號位)的其他位都取相反的值,得到反碼:1111 1011晨逝,最后加上1,得到數(shù)字-4的補碼:11111100支鸡,所以我們得到以下這個表:

數(shù)字 4 -4
原碼 0000 0100 1000 0100
反碼 0000 0100 1111 1011
補碼 0000 0100 1111 1100

小結(jié)一下趁窃,原碼到補碼的步驟:

  • 1, 原碼取反(除了首位)瀑构,得到反碼
  • 2寺晌, 反碼+1,得到補碼

這個步驟一會兒還要用到呻征,先記一下陆赋。

而在計算機中嚷闭,為了運算簡便(只需要一套電路),數(shù)字的存儲都是存儲的補碼凌受,所以數(shù)字-4在存儲單元中的值并不是它的原碼1000 0100胜蛉,而是它的補碼誊册,即1111 1100暖璧。同樣的,數(shù)字4存放的也不是二進制0000 0100嘲碱,而是它的補碼:0000 0100(由于是正數(shù),所以這兩個值相同麦锯,但不應(yīng)該理解為單純地存儲二進制數(shù))扶欣。

~運算

OK,現(xiàn)在我們有了理論的基礎(chǔ)料祠,我們再來討論按位非~運算。

~是一個單目運算符敛苇,它的定義是這樣的:

表達式中的任何一位為 1接谨,則結(jié)果中的該位變?yōu)?0。 表達式中的任何一位為 0脓豪,則結(jié)果中的該位變?yōu)?1忌卤。 --------摘自MSDN

也就是說笤闯,~運算的過程是這樣的棍厂,將要運算的數(shù)轉(zhuǎn)換為補碼牺弹,然后所有值為0的位變成1,值為1的位變?yōu)?晶默。即:

var m = ~3; // 對數(shù)字3執(zhí)行 按位非 運算
// 3 在計算機中存儲的值為 0000  0011
// 按位非之后航攒,變成了 1111 1100
// 請記住這是一個補碼,它代表的是十進制的數(shù)字 -4(上面的表格↑),所以m的值是 -4
 console.log(m); //  -4

那這個值怎么計算呢坞靶?我們再來一次圆丹,計算~25的值:

var n = ~25; // 對數(shù)字25執(zhí)行 按位非 運算
// 25的補碼是 0001 1001
// 按位非之后,1110 0110
// 這個就是計算的結(jié)果硝枉,這個結(jié)果是一個補碼倦微。但是這個補碼怎么轉(zhuǎn)換為十進制呢欣福?我們可以將原碼到補碼的計算過程倒過來進行計算。只要通過這個補碼得到原碼雏逾,就知道十進制是多少了郑临。

// 補碼-1厢洞,得到反碼
// 反碼按位取反(除了首位),得到原碼

// 1110 0110    <-- 補碼
// 補碼減1 得到1110 0101 <--  反碼
// 除了首位丧叽,其他位按位取反
// 得到1001 1010 <-- 原碼
// 觀察首位公你,為1陕靠,表示這是負數(shù),除去首位懦傍,剩下的二進制為 11010 ,即26
// 所以結(jié)果為 -26
console.log(n); // -26

另外粗俱,就像左移運算<<虚吟、右移>>等按位運算符在其他語言里一樣,~運算在其他語言里也是可以使用的偏塞,使用方法完全相同。

~~運算

由上面的例子擴展一下灸叼,如果是兩次取反古今,自然結(jié)果就變回來啦。特別要注意的是如果~后面的表達式不是int值氓拼,而是bool值或者字符串或者其他值得話桃漾,計算機會把表達式強制轉(zhuǎn)換為int再計算拟逮。

也就是說唱歧,~~會把后面的表達式強行變成int。

var n = ~~5; // 5
var m = ~~-8; // -8
var j = ~~true; // 將true轉(zhuǎn)換為int几于,也就是1沿彭,然后再計算尖滚。結(jié)果為1

!!運算

講到這里不得不提一下以前經(jīng)常使用的!!運算符漆弄,這個運算可以把表達式強行轉(zhuǎn)換為邏輯值,這個和上面提到的~~類似廉邑。這種小技巧一樣適合其他語言。

if ( !!localStorage.getItem( "highScore" ) ){
    localStorage.setItem( "highScore", "0" );
}

寫在最后

寫到這里特別想感慨一下,每個coder都有各自的編碼習(xí)慣蛛蒙,這種習(xí)慣一旦養(yǎng)成糙箍,想要改變是非常難的,所以希望大家在使用這些技巧之前牵祟,要考慮這種技巧的優(yōu)劣深夯,以免養(yǎng)成了不好的習(xí)慣,很難糾正掉诺苹。我用到這些奇巧淫技的地方是非常少的咕晋,理由很簡單,我不希望別人閱讀我的代碼非常吃力筝尾。像這種C語言風(fēng)格的代碼也許本就不應(yīng)該出現(xiàn)在js這種面向?qū)ο笳Z言中吧捡需。

閱讀別人的代碼也能夠看出別人的性格特點,如果別人寫出這樣的代碼給我閱讀筹淫,我可能會覺得這個人非常特立獨行。而我們公司也許并不需要這種特立獨行饰剥,作為研究學(xué)習(xí)尚可,但是實際應(yīng)用中顾孽,還是希望閱讀這篇文章的閣下,請避免寫出這樣的代碼蜒什。

所以我是反對過度使用奇巧淫技的霎冯。

啰嗦

由于在下水平有限,可能在文中有多處表達錯誤或不準確的地方缠俺。如果閣下在文章里發(fā)現(xiàn)在下寫的有失水準,還請不吝賜教墓卦,在評論指出。轉(zhuǎn)載請注明出處。如果希望鼓勵一下作者凡泣,點個贊就好鞋拟。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末褪测,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子项阴,更是在濱河造成了極大的恐慌环揽,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異漏策,居然都是意外死亡掺喻,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人层皱,你說我怎么就攤上這事∥驮觯” “怎么了?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵隙赁,是天一觀的道長。 經(jīng)常有香客問我弟灼,道長勤哗,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任诱咏,我火速辦了婚禮焚辅,結(jié)果婚禮上早处,老公的妹妹穿的比我還像新娘默责。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著怜校,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上键科,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天饭玲,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛葛假,可吹牛的內(nèi)容都是我干的带斑。 我是一名探鬼主播敢靡,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼贝椿,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎驳庭,沒想到半個月后贝淤,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體布隔,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡沉眶,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年腻暮,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡济榨,死狀恐怖叉弦,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布川无,位于F島的核電站仅叫,受9級特大地震影響洪灯,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽曲尸。三九已至蛾绎,卻和暖如春顽爹,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背杨赤。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工霎苗, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留桥爽,地道東北人缀去。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓校焦,卻偏偏與公主長得像耸成,于是被迫代替她去往敵國和親骗卜。 傳聞我的和親對象是個殘疾皇子烤宙,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,786評論 2 345

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

  • 網(wǎng)站亂碼問題我們會經(jīng)常碰到,大多見于非英文的中文字符或其他字符亂碼泳桦,而且浮毯,這類問題常常是因為編碼方式問題器虾,主要原因...
    波段頂?shù)?/span>閱讀 2,819評論 1 9
  • 1.編譯程序(1)gcc xx.c,他會默認生成一個a.out的可執(zhí)行文件库正,在a.out所在目錄抚垃,執(zhí)行./a.o...
    萌面大叔2閱讀 1,260評論 0 1
  • Java源碼 Integer Integer的簽名如下,繼承了Number類并實現(xiàn)Comparable接口 Com...
    wngn123閱讀 1,244評論 0 2
  • C語言基礎(chǔ) 編譯程序 gcc xx.c,他會默認生成a.out的可執(zhí)行文件,在a.out所在目錄,執(zhí)行./a.ou...
    帥碧閱讀 622評論 1 3
  • 1.編譯程序 (1)gcc xx.c,他會默認生成一個a.out的可執(zhí)行文件绽榛,在a.out所在目錄婿屹,執(zhí)行./a....
    萌面大叔2閱讀 460評論 0 1