HelloChunWei/blog

Javascript 邏輯運算子(AND OR) 再理解

Opened this issue · 0 comments

前言

AND OR 運算子絕對是大家耳熟能詳的運算子,相信剛學程式沒多久就會學到這兩個。最近在找資料的時候發現:以往對於邏輯運算子的理解好像不是很精確。

你會怎麼翻譯?

看看以下的code,在心中大家是怎麼翻譯的?

let gender = 'male';
let age = 20;

if (gender == 'male' && age >= 18) {
    console.log('要服兵役');
} else {
 console.log('目前不用服兵役');
 // 可能是女生,或者年齡還沒到
}

如果是男生且年齡超過18: 要服兵役,否則不用。

我想大多數人都是這樣理解這段code的,當然這樣理解也不能說有問題,只是程式運作上並不是像我們理解的這麼直觀。再看看以下的code:

if ('cat' && 'dog') {
    console.log('cat and dog')
} else {
    console.log('neither cat nor dog')
}

這段code 大家一定都知道他會跑到 if statement 裡面,會顯示出cat and dog。但這段code運用我們上一段的理解方式去翻譯的話感覺上就怪怪的?

如果狗跟貓存在 ???

當然實務上遇到的條件式不會這麼的簡單,但我相信大家多多少少都有遇到類似 if ('cat' && 'dog') 的情況。

文件怎麼說

如果要比較精準的理解if ('cat' && 'dog')我們就要去看看文件是怎麼解釋的,
我們就到MDN去重新理解一下吧。

先從 if 開始

文件裡面可以知道 if 的語法是

if (condition)
   statement1
[else
   statement2]

這一定是老生常談了,你知我知獨眼龍也知,比較重要的是 condition,我們來看看

condition
An expression that is considered to be either truthy or falsy.

這段是什麼意思呢?也就是條件式裡面的表達式是要能被轉換成 truthy value or falsy value。truthy value 以及 falsy value 如果有在寫 javascript 的多少都會知道,這就就不多闡述。

所以 if (truthy value) statement1 程式碼就會執行 if 內的 statement 程式。

現在我們比較精準知道 if 語法的執行,我們現在來看看邏輯運算子

邏輯運算子(AND OR)是會回傳值的

我們先從 && 開始:

expr1 && expr2
If expr1 can be converted to true, returns expr2; else, returns expr1.

從文件中可以知道,如果 expr1 可以會變轉換成 true,就 return expr2,不是的話 return expr1。

簡單來說:如果左邊的表達式為false 就回傳左邊的表達式,左邊為true就回傳右邊。當然如果遇到 expr1 && (expr2 && expr3) 就得先運行括號內的部分。

來看看簡單的範例:

a1 = true  && true
// a1 為 true
a2 = true  && false      
// a2 為false
a3 = false && true     
// a3 為false
a4 = false && (3 == 4)  
// a4 為false
a5 = 'cat' && 'dog'
//a5 為 'Dog'
a6 = false && 'cat'
// a6 為 false

從第五的範例可以知道 'Cat' && 'Dog' 會得到 'Dog',那現在再回到上面的 if statement吧

if ('cat' && 'dog') {
    console.log('cat and dog')
} else {
    console.log('neither cat nor dog')
}

if ('cat' && 'dog') 從 && 可以知道會回傳 'Dog' 所以這段code會變成 if ('Dog') 'Dog' 為truthy value 所以會執行 console.log('cat and dog')

現在換到 || :

基本上跟 && 就是相反的,

expr1 || expr2
If expr1 can be converted to true, returns expr1; else, returns expr2.

|| 會先判斷左邊 expr1 是否為 true 是的話就回傳 expr1 ,否則回傳 expr2。
所以 OR 運算子有個用法是設定預設值。

function foo (arg) {
    arg = arg || 'default'
    return arg
    // 根據運算子的規則, arg 如果不為 truthy value的話,就會是我們預設的 'default'
}

原理就是如此,如果想要判斷空字串跟0的話可以使用 Nullish coalescing operator 可以參考我之前寫的一篇文章

另外假設現在有段code:

let number = 5

if (number > 0) {
     console.log('number > 0')
} else {
    console.log('number < 0')
}

// 可以寫成:

number > 0 && console.log('number > 0')
number > 0 || console.log('number < 0')

另外今天我們有一個狀況是以下的話也可以做改寫:

let obj = {
    foo: 'foo'
}

let bar = 'bar'

if (bar) {
    obj.bar = bar
}
// 可以改寫成
// 運用展開運算子

let data = {
    ...obj,
    ...(bar ? {bar} : {})
}

// 也可以改寫成
bar && [obj.bar = bar]

Note: 由於 邏輯運算子會回傳值,所以不能直接 bar && obj.bar = bar,會報錯: Invalid left-hand side in assignment。要把他用 array 包起來,讓他回傳一個 [undefined] 的 array。

不過在使用上述寫法時,必須要考慮程式可讀性的問題,bar && [obj.bar = bar] 並不是相當的直觀,使用前可能需要多與團隊討論。(投資理財有賺有賠)

結論

重新理解運算子後得到了滿多有趣的知識,例如像上述的寫法,以及重新檢視以前對於 if () 的理解。當然不能說以前的理解是錯誤的,只能說是不太完整,藉由這次的機會去補全自己不足的地方。