本系列文章已重新編修,並在加入部分 ES6 新篇章後集結成書,有興趣的朋友可至天瓏書局選購,感謝大家支持。
購書連結 https://www.tenlong.com.tw/products/9789864344130
讓我們再次重新認識 JavaScript!
在上一篇文章當中,我們介紹了四則運算的算術運算子 (Arithmetic Operator),那麼在今天的分享當中,我們繼續來看看其他運算子吧。
昨天寫完之後才突然想起,算術運算子除了用來做「兩個數值」的四則運算、取餘數的作用以外,還有另外一種是只需要單個數值就可以完成運算,這類運算子通常會被稱為「一元運算子」 (Unary Operator)。
+
與負號 -
如同我們過去在學校所學的數學一樣,正號 +
與負號 -
分別用來表示數字的「正數」與「負數」的狀態。
var a = +10;
var b = -10;
console.log(a); // 10
console.log(b); // -10
但有趣的是,若是正號 +
與負號 -
後面帶的並不是一個數字型態的值,那麼 JavaScript 會在背後先透過 Number()
的方法嘗試著將其轉型,再看前面帶的是正號 +
或負號 -
來決定其數值。
var a = "+10";
var b = "-10";
var c = "Hello";
console.log( +a ); // 10
console.log( -a ); // -10
console.log( +b ); // -10
console.log( -b ); // 10
console.log( +c ); // NaN
console.log( -c ); // NaN
而物件型別的情況下,則是會先透過物件的 valueOf()
方法先求得對應的數值,再依照正號 +
或負號 -
來決定其數值。
如果得到 NaN
,那麼結果就是 NaN
。
+true // 1
+false // 0
+null // 0
+function(val){ return val;} //NaN
所以說,如果你覺得 Number()
太長,又想做數字轉型的話,透過加號 +
也會有一樣的效果。
++
與遞減 --
除了正號 +
與負號 -
之外,另一種更常見的一元運算子就屬「遞增」 ++
與「遞減」 --
了。
遞增與遞減就如同字面上意思一樣,當變數遇上了 ++
就會加一,而 --
就會減一:
var a = 10;
a++;
console.log(a); // 11
a--;
console.log(a); // 10
所以 ++
與 --
這兩個運算子,你可以把他們當作是: a = a + 1
與 a = a - 1
的意思。
但是除了遞增與遞減的功能外,++
與 --
這兩個運算子的位置也是有差別的喔。
這裏我們簡單做個比較:
var a = 10;
var b = 10;
a++;
console.log(a); // 11
++b;
console.log(b); // 11
我知道看完之後你可能會想翻桌,根本就一樣嘛。
別急,就結果來說, ++
放在變數前面與放在變數後面,是一樣的沒錯。
我們換個寫法再來一次:
var a = 10;
var b = 10;
console.log(a++); // 10
console.log(++b); // 11
console.log(a); // 11
console.log(b); // 11
看出差異了嗎?
當我們將 ++
放在變數後面時,回傳的結果會是「原始的數值」。
而 ++
放在變數前面時,得到的會是「+1 之後的結果」。
當然事後再將兩者印出時,就都會是 +1 之後的結果了, --
的概念也是一樣。
結束了算數運算子之後,接著我們要來看比較運算子。
比較運算子就是用來比較運算子兩側數值 (可能是純值、物件,甚至某個運算式或函數回傳的結果),比較後得到 true
或 false
。
針對不同型別的數值,JavaScript 會嘗試將它們在背景 (自動) 轉型到同樣型態後,再做比較。
==
與 「全等」 ===
很多朋友在剛接觸 JavaScript 的時候,應該都會搞不懂「兩個」等號 ==
與「三個」等號的差別 ===
,這裡就來詳細說明。
一個等號 =
的情況很單純,是「指定、賦值」的意思,像:
var a = 10;
此時會將等號右側的值 (10) 指定至變數 a
當中。
而若要比較數值的情況下,多數程式語言會用「兩個」等號 ==
,來為左右兩側的資料進行比較。
當然 JavaScript 也有:
var a = 10;
var b = 100;
console.log( a == b ); // false
console.log( a == 10 ); // true
看起來很 ok 對吧?
但是如果是兩個「資料型態」不同的比較呢?
var a = 10;
var b = "10";
猜猜看,此時 console.log( a == b );
會是 true
或是 false
?
答案是 true
。
這時候問題就來了,一個數字的 10
與字串的 "10"
居然會相等?
真不知道該說是 JavaScript 太貼心還是太不嚴謹。
如果是數字與字串也就算了,我們來看看下面這個例子:
true == 'true' // ?
false == 'false' // ?
來猜猜看,這兩個運算式的比較結果會是什麼? 答案都是 false
。
另外我們再來看看各種莫名其妙的比較判斷:
false == 0 // true
true == 1 // true
[] == [] // false
[] == ![] // true
[] == '' // true
[] == 0 // true
[''] == '' // true
[0] == 0 // true
[0] == '' // false
[''] == 0 // true
然後:
null == undefined // true
[null] == '' // true
[null] == 0 // true
[undefined] == '' // true
[undefined] == 0 // true
看完還覺得 JavaScript 如此貼心嗎? 是噁心吧
「JavaScript 我真是猜不透你啊~」
為什麼會這樣? 等等我們回頭來介紹 JavaScript 自動轉型的規則,你就知道了。
所以後來,為了排除這種奇怪的問題,於是就新增了「三個等號」===
這個比較運算子。
三個等號 ===
與兩個等號 ==
雖然都是比較的意思,但最大的差別在於「三個等號 ===
不會替數值做自動轉型」。 也就是說,回到一開始的例子:
var a = 10;
var b = "10";
console.log( a == b ); // true
console.log( a === b ); // false
在 ===
的情況下,數字的 10
與字串的 "10"
,由於 JavaScript 不會做自動轉型,所以結果會是 false
,它只會在雙方的數值與型態都相等的狀況下回傳 true
。
而原本 null == undefined
的情況下會得到 true
,改成 null === undefined
之後,得到的會是正確的 false
。
這也是為什麼在 JavaScript 這門程式語言中,大家會提倡盡量使用 ===
來取代 ==
的原因。
!=
與 !==
除了判斷是否相等以外,與之對應的還有「不等於」。
當然不等於也分成 !=
與 !==
兩個版本: !=
的版本會做自動轉型,而 !==
則不會做自動轉型。
就觀念上來說都是一樣的,這裡就不再贅述。
前面提到,在兩個等號 ==
的比較運算式下,若是雙方的資料類型不同時,則會進行「自動轉型」,那麼這裡就來說明自動轉型的規則。
true
轉型為「數字」的 1
, false
則會變成數字的 0
Number()
嘗試轉型為數字後,再進行比較。valueOf()
方法取得對應的基本型別的值,再進行比較。除此之外,還有前面文章曾提到過的:
NaN
不等於 NaN
,不管是兩個等號或三個等號都一樣。true
。>
與小於 <
除了判斷是否相等以外,當然也有為數值的「大小」來做比較。
使用的運算子就是大家都很熟悉的大於 >
、小於 <
、大於等於 >=
,以及小於等於 <=
符號。
var a = 10;
var b = 11;
var c = 10;
console.log( a > b ); // false
console.log( b > a ); // true
console.log( a > c ); // false
console.log( a >= c ); // true
當然此類運算子也會遇到不同型別要「自動轉型」的狀況,規則大致如下:
true
看成 1
, false
看成 0
再進行比較。valueOf()
方法先求得對應的數值,若物件沒有 valueOf()
方法的話,則會透過 toString()
轉型再進行比較。另外, =>
不是運算子,是 ES6 的箭頭函式,後續我們會來介紹這個東西,小心不要搞錯了。
「自動轉型」一直是 JavaScript 初學者很容易搞混的地方,希望透過今天的介紹可以幫助各位理解,如果覺得不過癮的話,還可以參考「JS 真值表」
保證讓你剛入門就放棄 (欸
別擔心,正常情況下,大部分的奇怪狀況你應該都不會遇到。
那麼感謝各位一路看到最後,以上就是今天分享的內容。
大大的文章寫得真好,
這段程式我自己實驗答案是 10
,是各家瀏覽器實作的問題嗎?
console.log( -b ); // -10
還有這裡應該是大大筆誤了 XD
改成 null === undefined
之後,得到的會是正確的 true
console.log( -b );
那段確實是我複製時貼錯了,負負得正,所以是 10 才對。
已修正,謝謝提醒 XD
另外, null
與 undefined
在 ===
的結果會是 false
喔 (已更新)