深入了解JavaScript的邏輯運(yùn)算符(與、或)
十二月已經(jīng)過(guò)半,冬季是一個(gè)美妙的季節(jié),寒冷的空氣逼得人們不得不躲在安逸舒適的環(huán)境里生活。冬季會(huì)給人一種安靜祥和的氛圍,讓人沉浸在其中,仿佛是一個(gè)舊的階段的結(jié)束,同時(shí)也是一個(gè)新的階段的開(kāi)始。這么說(shuō)來(lái),西方和中國(guó)的圣誕節(jié)和春節(jié)都選擇在了冬季也不是沒(méi)有道理,在一年中最寒冷的時(shí)候,人們擁簇在溫暖的環(huán)境里,彼此訴說(shuō)著過(guò)去一年里自己的成就,展望著新的一年里美好的愿望,相互掛念的人團(tuán)聚,天氣的寒冷和人情的溫暖形成了強(qiáng)烈的對(duì)比。而在天寒地凍之中,仿佛更有利于人們思考,去探尋知識(shí)的真諦。
這次想分享的是 JS 當(dāng)中的邏輯運(yùn)算符與、或,也就是 && 、 || ,初來(lái)乍到的同學(xué)們看到這里就會(huì)覺(jué)得沒(méi)趣了,這玩意有什么好分享的,剛開(kāi)始學(xué) JS 的時(shí)候不就會(huì)了嗎,我用了無(wú)數(shù)遍都沒(méi)有什么問(wèn)題啊。而有經(jīng)驗(yàn)的同學(xué)可能會(huì)陷入沉思,難不成這其中會(huì)有什么奧秘所在?沒(méi)錯(cuò),別看這簡(jiǎn)簡(jiǎn)單單的幾個(gè)運(yùn)算符,雖然這是最基礎(chǔ)的知識(shí),但其中隱藏的奧秘卻十分耐人尋味,接下來(lái)我就為大家一一揭開(kāi)這簡(jiǎn)答的運(yùn)算符背后的奇妙之處。
基礎(chǔ)的作用我就不說(shuō)了,這兩個(gè)符號(hào)是個(gè)程序員都能明白,這里首先我想先來(lái)說(shuō)一說(shuō) JS 當(dāng)中的隱式轉(zhuǎn)換。
眾所周知,JS 在做邏輯判斷的時(shí)候會(huì)自動(dòng)將非布爾類(lèi)型的值進(jìn)行隱式轉(zhuǎn)換,轉(zhuǎn)換成布爾類(lèi)型的值然后在進(jìn)行邏輯運(yùn)算。在初學(xué) JS 的時(shí)候,都會(huì)講到在隱式轉(zhuǎn)換中,除了幾個(gè)特定的假值,其他的均會(huì)轉(zhuǎn)換成真值,這些假值有:
NaN; ""; undefined; null; 0;
有了這些隱式轉(zhuǎn)換的規(guī)則,便構(gòu)成了 JS 當(dāng)中邏輯運(yùn)算的核心基礎(chǔ)。
其實(shí)在 JS 當(dāng)中,要說(shuō)“邏輯運(yùn)算符”其實(shí)并不完全正確,Kyle Simpson 在《You Don't Know JS》系列書(shū)當(dāng)中提到:“與其說(shuō)是‘邏輯運(yùn)算符',不如說(shuō)是‘選擇器運(yùn)算符'。” 為什么大師要這樣說(shuō)呢?其實(shí)我們大多數(shù)人都被 JS 的表象給蒙蔽了,比如下面一段非常簡(jiǎn)單的代碼:
if( "hello" && 0 ) { console.log(true); } else { console.log(false); }
如果你對(duì) JS 了解的不夠深刻,你可能會(huì)這樣解釋這段代碼:首先在邏輯判斷中,"hello" 是一個(gè)真值,0 是一個(gè)假值,一個(gè)真值和一個(gè)假值進(jìn)行與運(yùn)算,結(jié)果為 false 。這也可能是大多數(shù)人的理解,但其實(shí)不然,其內(nèi)部的原理可不止這么簡(jiǎn)單,因?yàn)?&& 和 || 返回的并不是判斷條件的真假 ,而是判斷條件中的一個(gè)原始值。它將依次對(duì)條件判斷中的值進(jìn)行判斷,如果是非布爾值,則轉(zhuǎn)換成布爾值做判斷,然后再根據(jù)判斷條件來(lái)決定返回哪一個(gè)值。
對(duì)于 && :該運(yùn)算符返回條件語(yǔ)句中的第一個(gè)假值,如果所有的值都為真,則返回最后一個(gè)值,&& 也被稱(chēng)為 “守護(hù)運(yùn)算符” 。比如下面一段代碼:
var a = "hello" && "world"; console.log(a); //world var b = 0 && 1; console.log(b); //0
可以看出,邏輯運(yùn)算符其實(shí)返回的并不是條件的真假,而是原始值。如果條件語(yǔ)句中有多個(gè) && 運(yùn)算符,則一樣遵循以上原則,從左向右依次判斷,如果遇到了假值,就返回該假值,如果所有值都為真,則返回最后一個(gè)值。
對(duì)于 ||:該運(yùn)算符與 && 運(yùn)算符相反,它返回條件語(yǔ)句中的第一個(gè)真值,如果所有值都為假,則返回最后一個(gè)值。比如下面一段代碼:
var a = "hello" || 0; console.log(a); //hello var b = 0 || NaN; console.log(b); //NaN
同樣,|| 返回的也不是布爾值。如果有多個(gè) || 則同樣遵循相同的原則,從左向右依次掃描。
講到這里也就來(lái)到了本篇文章的核心,在 JS 當(dāng)中,條件判斷語(yǔ)句都是建立在隱式轉(zhuǎn)換之上的,也就是說(shuō)所謂的邏輯運(yùn)算符,實(shí)際上是在條件判斷語(yǔ)句中從左向右依次掃描,如果是一個(gè)布爾值,則判斷該布爾值的真假,如果是一個(gè)非布爾值,則先對(duì)該值進(jìn)行隱式轉(zhuǎn)換,然后再判斷真假,如果滿(mǎn)足條件,則返回該值,如果沒(méi)有滿(mǎn)足條件值,則返回最后一個(gè)值,然后在對(duì)返回的這個(gè)值做判斷,如果是一個(gè)布爾值,則直接判斷,如果是一個(gè)非布爾值,則先隱式轉(zhuǎn)換成布爾值,再做判斷。所以我們也可以把 && 稱(chēng)為 “取假運(yùn)算符” ,把 || 稱(chēng)為 “取真運(yùn)算符” ,因?yàn)檫@兩個(gè)運(yùn)算符的實(shí)質(zhì)都是取條件語(yǔ)句中的第一個(gè)真值或者假值,如果始終沒(méi)有找到,則返回最后一個(gè)值。而這樣的算法也恰好滿(mǎn)足邏輯判斷的需求,比如 && 運(yùn)算符,如果所有的值都是真值,那么返回哪個(gè)值其實(shí)都無(wú)所謂,因?yàn)樗兄刀寄軌虮浑[式轉(zhuǎn)化為 true ,而只要有一個(gè)假值,則判斷條件不成立,所以會(huì)返回第一個(gè)遇到的假值。而 || 運(yùn)算符,如果所有的值都是假值,返回任意一個(gè)都會(huì)被隱式轉(zhuǎn)換成 false ,但只要遇到了一個(gè)真值,則判斷條件成立,所以會(huì)返回第一個(gè)遇到的真值。&& 和 || 運(yùn)算符都是 “短路” 的。
所以我們可以自己實(shí)現(xiàn)一個(gè)邏輯運(yùn)算的函數(shù):
// && 等價(jià)于: function AND () { for (var i = 0; i < arguments.length; i++) { if (!arguments[i]) { return arguments[i]; } } return arguments[i-1]; }
// || 等價(jià)于: function OR () { for (var i = 0; i < arguments.length; i++) { if(arguments[i]) { return arguments[i]; } } return arguments[i-1]; }
(注:在這里我同時(shí)也想對(duì) ! 這個(gè)運(yùn)算符做講解,但考慮到內(nèi)容和篇幅的問(wèn)題,暫時(shí)不做深入探究,僅做簡(jiǎn)單講述。 ! 運(yùn)算符實(shí)際上運(yùn)行機(jī)制與 && 和 || 是一樣的,首先會(huì)對(duì)參數(shù)值做判斷,如果是一個(gè)布爾值,則進(jìn)行取反運(yùn)算,如果是一個(gè)非布爾值,則先進(jìn)行隱式轉(zhuǎn)換,再進(jìn)行取反運(yùn)算。而我們通常寫(xiě)的 if (something) 語(yǔ)句,實(shí)際上的意思 if (!!something))
然后我們可以這樣使用:
var a = ["hello", undefined, "world"]; console.log(AND.apply(null, a)); //undefined var b = ["", 0, NaN]; console.log(OR.apply(null, b)); //NaN
進(jìn)而,我們就可以推斷出一下結(jié)論:
a = x || y; //等價(jià)于: a = x ? x : y; a = x && y; //等價(jià)于: a = x ? y : x;
這通常也是一些壓縮工具所做的事情,它們盡可能的將繁雜的條件判斷語(yǔ)句轉(zhuǎn)換成 && 或者 || ,因?yàn)檫@樣代碼更加的精簡(jiǎn),但是可讀性則就不那么可觀了。
對(duì)于最開(kāi)始的那一段代碼:
if( "hello" && 0 ) { console.log(true); } else { console.log(false); }
我們現(xiàn)在就要這樣解釋?zhuān)菏紫冗@是個(gè)與運(yùn)算符,與運(yùn)算符的作用是取第一個(gè)假值,如果所有的值都為真,那么則返回最后一個(gè)值。所以在這條語(yǔ)句中,第一個(gè)值是 "hello" ,因?yàn)樵撝凳且粋€(gè)非布爾值,JS 引擎會(huì)先將它隱式轉(zhuǎn)換成布爾值,而該值不在假值的范圍內(nèi),所以會(huì)被轉(zhuǎn)化成 true 。隨后 JS 引擎會(huì)繼續(xù)查找,第二個(gè)值是 0 ,該值同樣也不是一個(gè)布爾值,所以 JS 引擎也會(huì)先將它隱式轉(zhuǎn)換成布爾值,而該值在假值的范圍內(nèi),所以會(huì)被轉(zhuǎn)化成 false ,滿(mǎn)足 && 運(yùn)算符的查找條件,則將值 0 返回。而條件判斷語(yǔ)句接受到了值 0 ,該值不是一個(gè)布爾類(lèi)型的值,所以會(huì)先對(duì)它進(jìn)行隱式轉(zhuǎn)換,而該值在假值范圍內(nèi),所以會(huì)被轉(zhuǎn)化成 false ,然后控制臺(tái)會(huì)輸出 false。
所以說(shuō)以后當(dāng)我們看到 && 和 || 時(shí)候,就不要僅僅的從字面上的意義去理解了,在看完了這篇文章之后,你就可以很自豪很有底氣的對(duì)別人說(shuō),你真的會(huì)用邏輯運(yùn)算符嗎?
好了,就這么兩個(gè)小玩意居然背后也有著這么多的精髓,看來(lái)知識(shí)的深度是無(wú)窮的,冬季還真是一個(gè)能引發(fā)人們思考的季節(jié)。圣誕節(jié)即將到來(lái),在這里提前預(yù)祝大家圣誕快樂(lè),Merry Christmas!
以上就是本文的全部?jī)?nèi)容,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作能帶來(lái)一定的幫助,同時(shí)也希望多多支持腳本之家!
相關(guān)文章
微信頁(yè)面倒計(jì)時(shí)代碼(解決safari不兼容date的問(wèn)題)
本文主要分享了微信頁(yè)面倒計(jì)時(shí)代碼(pc端),并在文章結(jié)尾分析了safari不兼容date的原因以及解決方法,具有很好的參考價(jià)值,需要的朋友一起來(lái)看下吧2016-12-12javascript觀察者模式實(shí)現(xiàn)自動(dòng)刷新效果
這篇文章主要為大家詳細(xì)介紹了javascript觀察者模式實(shí)現(xiàn)自動(dòng)刷新效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-09-09使用PBFunc在Powerbuilder中支付寶當(dāng)面付款功能
這篇文章主要介紹了使用PBFunc在Powerbuilder中支付寶當(dāng)面付款功能的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-10-10前端實(shí)現(xiàn)截屏的兩種常見(jiàn)方式
這篇文章主要介紹了前端實(shí)現(xiàn)截屏的兩種常見(jiàn)方式,分別是使用第三方庫(kù)html2canvas和navigator.mediaDevices.getDisplayMedia,兩種方法都給出了詳細(xì)的代碼示例,需要的朋友可以參考下2025-03-03JavaScript XML實(shí)現(xiàn)兩級(jí)級(jí)聯(lián)下拉列表
用xml作為存儲(chǔ)容器,不用數(shù)據(jù)庫(kù),速度和效率高些。2008-11-11JS數(shù)組操作(數(shù)組增加、刪除、翻轉(zhuǎn)、轉(zhuǎn)字符串、取索引、截取(切片)slice、剪接splice、數(shù)組合并)
這篇文章主要介紹了JS數(shù)組操作(數(shù)組增加、刪除、翻轉(zhuǎn)、轉(zhuǎn)字符串、取索引、截取(切片)slice、剪接splice、數(shù)組合并)的相關(guān)資料,需要的朋友可以參考下2016-05-05JS實(shí)現(xiàn)自動(dòng)變化的導(dǎo)航菜單效果代碼
這篇文章主要介紹了JS實(shí)現(xiàn)自動(dòng)變化的導(dǎo)航菜單效果代碼,涉及JavaScript基于定時(shí)函數(shù)觸發(fā)頁(yè)面元素屬性動(dòng)態(tài)變換的技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-09-09