本系列文章已重新編修,並在加入部分 ES6 新篇章後集結成書,有興趣的朋友可至天瓏書局選購,感謝大家支持。
購書連結
https://www.tenlong.com.tw/products/9789864344130
讓我們再次重新認識 JavaScript!
運算子系列總算要來到最終篇了。
如同先前所說,礙於篇幅的關係只會列出常見、以及大家在學習 JavaScript 最容易被搞混的部分。
如果要了解完整的內容可詳閱:
MDN-運算式與運算子
。
指派運算子 (Assignment Operator)
在前面的文章中,我們曾經提到過
++
與
--
運算子,分別為我們處理變數的「遞增」與「遞減」。
那麼如果我們要處理的運算,不是 「+1」,而是「+2」、「+3」的話,有沒有更簡便的寫法呢?
這時候就可以利用指派運算子 (Assignment Operator) 來幫助我們。
最基本的指派運算子就是大家都很熟悉的
=
,一個等號來表示。
var a = 10 * 100;
像上面範例中,我們用 =
符號將右側的運算式結果「指派」(assign) 至等號左側的變數 a
。
除了最基本的用法之外,還可以結合數學運算子:
var a = 10;
a += 100; // 代表 a = a + 100;
console.log( a ); // 110
a += 100
代表 a = a + 100
也就是說,會先將 =
右側的 a + 100
計算完成後,然後再指定至變數 a
內。
當然,行爲也會與數學運算子一樣的是, +=
前後都是「數值」或「布林值」的話,則會視為數字後相加,而若有其中一方為字串,則會視為字串來連結。 這部分前面也已介紹過就不再贅述。
下面簡單列出常見的指派運算子:
逗號運算子
「逗號運算子」主要的工作讓逗號分隔運算式可以循序執行 (由左至右) ,並且會回傳最後一個運算式的值。
如果需要在一個運算式裡面同時包含多組運算式的話,就可以用「逗號」 ,
來將它們分開。
最常出現的地方應該是 for
迴圈:
for (i = 0, j = 10; i < 10; i++, j++) {
k = i + j;
透過 ,
運算子可以將多組運算式看做是一個。
另外還有個常見的場景,就是「宣告」變數的時候:
var a = 10;
var b = 10;
像上面的 a
與 b
可以寫成:
var a = 10, b = 10;
這樣就可以同時宣告多組變數,且給予預設值。
但是,有個需要注意的地方就是,有些朋友可能會寫成這樣:
var a = b = 10;
console.log(a); // 10
console.log(b); // 10
喔喔! 同時宣告兩個變數,而且 a
與 b
同時都給予 10
的預設值了!
逼逼! 像這樣看似很方便的寫法,其實是有大問題的!
那麼 var a = b = 10;
出了什麼問題呢?
一開始我們有說過,沒有 var
宣告的變數都會變成「全域變數」對吧?
你可能會說 var a = b = 10;
有啊,前面有 var
,但事實上,這段程式碼拆來來看是這樣的:
b = 10;
var a = b;
看出來了嗎? 實際上變數 b
是沒有透過 var
來做宣告的。
換言之,你可能在無意間創造了一個全域變數,而你卻沒發現:
(function(){
var a = b = 10
console.log(a, b); // 10, 10
})();
// 離開了變數作用範圍的 a 會變成 undefined
// 而 b 卻變成全域變數而保留了狀態
console.log(a, b); // undefined, 10
往後我們會介紹到變數的作用範圍,這裡讓各位有個印象即可。
邏輯運算子 (Logical Operator)
再來是今天的重頭戲:「邏輯運算子」。
如果你曾經用過其他程式語言來開發的話,你可能會覺得...
這有什麼好值得說明的,不就 AND &&
、 OR ||
還有 NOT !
三種嗎?
運算後我應個會得到一個「boolean」的值,不是 true
就是 false
嘛。
如果你也是這樣想的話,那麼接下來的部分很值得繼續看下去。
來看看這份範例:
var a = 123;
var b = "abc";
var c = null;
console.log( a && b ); // "abc"
console.log( a || b ); // 123
console.log( c && a ); // null
console.log( c || b ); // "abc"
console.log( c || a ); // 123
看到了嗎? 說好的 true
跟 false
呢?
在講解前上面的詭異狀況前,先來說明一下,
「AND &&
」:用兩個 &
符號來表示,在「多數程式語言」中代表的意義是:
「(條件/運算式A) && (條件/運算式B)」當 &&
左右兩側的值同時為 true
時,則會得到 true
的結果。 若其中一方是 false
的情況下,則得到 false
。
「OR ||
」:用兩個 |
(pipe) 符號來表示,在「多數程式語言」中代表的意義是:
「(條件/運算式A) || (條件/運算式B)」當 ||
左右兩側的值只要有一方為 true
,則結果為 true
。 只有在兩側皆為 false
的情況下才會得到 false
。
「NOT !
」:以一個 !
驚嘆號來表示,原本是 true
的結果經過 !
轉換後會得到 false
,而 false
會變成 true
。 所以你可能會看到很多人用 !!xxx
來取代 Boolean(xxx)
,透過兩次的「NOT」操作,即可判斷某數值 Boolean 轉換後的結果。
嚴格來說,只有「NOT !
」運算子才會回傳 true
或 false
。
你可能會說,可是我在 if
條件式裡面,代入
if( a && b ) { ... }
if( a || b ) { ... }
這類的寫法,都可以正常執行啊?
在 JavaScript 這門程式語言當中,我們可以分成兩種「值」:
那些經過 ToBoolean
轉換後得到 false
的值
以及其他的值,通常這些最後都會變成 true
這不是在講廢話,我知道你看完都硬了,快收起你的拳頭。
Falsy 與 Truthy: 論 Boolean 的型別轉換
前面講過,JavaScript 這門程式語言,我們可以分成兩種「值」,第一種就是經過 ToBoolean
轉換後會變成 false
的部分:
Undefined
+0
, -0
, or NaN
空字串 ""
或 ''
來源: ECMAScript® 2017 Language Specification: 7.1.2 ToBoolean
不是我在豪小,真的有規範對吧。
如果是上面列出的幾種情況,那麼透過 ToBoolean
轉換就會變成 false
,而其他的部分都會是 true
。
而那些轉換後會得到 false
結果的,我們通常稱這些叫 「falsy」值,而其他會變成 true
的部分,則是 「truthy」值。
聽起來好像很好理解嘛,讓我們來猜猜下面程式片段會得到什麼:
Boolean("false") // ?
Boolean("0") // ?
Boolean("''") // ?
猜對了嗎? 答案都是 true
。
裡面只有 "''"
看起來比較像 false
,但規範裡寫著是「空字串」 ""
或 ''
,可不是「雙引號包覆單引號」喔。
然而還有一些容易讓人搞混的地方:
Boolean( {} )
Boolean( [] )
Boolean( function(){} )
以上這些也都是 true
。
所以再複習一次:
那些經過 ToBoolean
轉換後得到 false
的值
以及其他的值,通常這些最後都會變成 true
判斷 false
比判斷 true
要來得簡單對吧!
再回到邏輯運算子
事實上,「AND &&
」與「OR ||
」分別代表「且」與「或」的意思沒錯,但一開始的範例為什麼會是:
var a = 123;
var b = "abc";
var c = null;
console.log( a && b ); // "abc"
console.log( a || b ); // 123
console.log( c && a ); // null
console.log( c || b ); // "abc"
console.log( c || a ); // 123
說好的 true
跟 false
呢? 誰跟你說好
來看看 ECMAScript: 12.13Binary Logical Operators 規範怎麼說:
The value produced by a && or || operator is not necessarily of type Boolean. The value produced will always be the value of one of the two operand expressions.
簡單來說,透過 &&
或 ||
所產生的值不一定會是 Boolean
,而是兩者其中之一。
&&
與 ||
運算子在判斷的時候,會先對左邊的數值進行檢查。
如果是 Boolean
類型就再做後續的判斷,如果不是?那就會透過 ToBoolean
判斷是「falsy」或「truthy」來轉換成對應的 true
跟 false
。
對 ||
運算子來說,若第一個數值轉換為 true
,則回傳第一個數值,否則回傳第二個數值。
對 &&
運算子來說,若第一個數值轉換為 true
,則回傳第二個數值,否則回傳第一個數值。
所以,在 if
條件判斷當中,JavaScript 會針對回傳後的數值再度做 ToBoolean
判斷是「falsy」或「truthy」,
這也就是為什麼在 &&
與 ||
的結果可以用來當作 true
與 false
的判斷了。
所以說,未來如果看到這類想騙人的題目:
!!'false' == !!'true' // ?
!!'false' === !!'true' // ?
相信你應該可以知道答案是什麼了吧!
那麼以上就是今天分享的重點,希望各位在遇到「真假」轉換的時候不會再上當受騙。
下回我們要繼續來介紹流程控制的部分,感謝大家收看。 掰。
1.那些經過 ToBoolean 轉換後得到 false 的值
2.以及其他的值,通常這些最後都會變成 true
我搞不太懂,這邊提到的值,跟前面陣列、物件章節提到的基本型別值(如:string、boolean、number)、物件值。
這兩篇提到的「值」名詞解釋上的差異在哪呢?
你好,JavaScript 以變數型態來說,主要分為「基本型別」與「物件型別」,這個部分相信不用我多做解釋了。
而不管是基本型別或物件型別的變數,兩者都可以透過 ToBoolean
轉換成 true
或 false
的「值」。
所以我們可以直接將某個變數做為流程判斷的條件,如:
let obj = {};
if ( obj ) {
// ...
這篇文章想說明的是,哪些東西經過轉型後會變成 true
,而哪些又會變成 false
。