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