keywords:coercion boolean
,運算子 || 、 &&
隱含地:Boolean
何種運算式的作業需要隱含地強制轉換為 boolean?
- 一個 if(..) 述句中的測試運算式
- 一個 for( .. ; .. ; .. ) 標頭中的測試運算式 ( 第二個子句 )
- while(..) 與 do..while(..) 迴圈中的測試運算式
- ? : 三元運算式中的測試運算式 ( 第一個句子 )
|| 和 && 運算子左邊的運算元
let a = 99; let b = 'xyz'; let c; let d = null; if(a){ console.log('omg'); // omg } while(c){ console.log('never run this'); } c = d ? a : b; c; // 'xyz' if((a && d) || c){ console.log('omg'); // omg }
運算子 || 與 &&
- 這些運算子不應該被稱為邏輯的運算子,應該稱它們為選擇器運算子或更完整的是運算元選擇器運算子
- 因為在 JS 裡面它們實際上並不會產生一個邏輯值,跟其他程式語言不同,它們會選擇兩個運算元其中一個的值
- 引述 2021 規格的 12.13 Binary 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 型別,而是兩個運算元運算式其中一個的值
let a = 98;
let b = 'xyz';
let c = null;
a || b; // 98
a && b; // 'xyz'
c || b; // 'xyz'
c && b; // null
&& 與 || 運算子會在第一個運算元上進行 boolean 測試,如果該運算元尚不是 boolean 值,就會發生正常的 ToBoolean 強制轉型
|| 運算子:第一個對就停下來取第一個
&& 運算子:兩個都要對,所以第一個對就會取第二個
a || b; 大略等同於: a ? a : b null ? null : 99; // 99 99 ? 99 : null; // 99 a && b; 大略等同於: a ? b : a null ? 99 : null; // null 99 ? null : 99; // null
|| 此種行為極為常見且相當有幫助的用法:
function f1(a,b) { a = a || 'oh'; b = b || 'my god!'; console.log(a + ' ' + b); } f1(); // 'oh my god!' f1('hi','everyone!'); // 'hi everyone!'
這種慣用法就是提供一個備用的預設值 ('oh'),但要小心
f1('Game over!',''); // 'Game over! my god!'
因為第二個引數的 '' 是一個 falsy 值 ( 還記得是哪五項 8 個嗎 ),所以 b = b || 'my god!' 會回傳 'my god!',即使這裡的意圖可能是真的明確要傳入 '' 作為指定給 b
這個 || 慣用法極為普遍,也相當有幫助但只能在『 所有的 falsy 值都應該被跳過 』的情況下使用,否則你的測試就得更明確,或許要改用 ?: 三元運算子才是&& 有一個慣用手法較少手動使用,不過經常被 JS 縮小器所用,&& 運算子只在第一個運算元的測試結果是 truthy 時才會選擇第二個運算元 ( a ? b : a ),這種用法常被稱為守護運算子 ( guard operator )
function f1() { console.log(a); } let a = 99; a && foo(); // 99 f1() 只在 a 測試結果是 truthy 時被呼叫,如果測試失敗了就會安靜地停止,不會呼叫 f1() 通常人們都會用: if(a){ foo(); } JS 縮小器會用: a && foo();
let a = 99; let b = null; let c = 'xyz'; if(a && ( b || c )){ console.log('hi'); // 'hi' } 實際上所產生的是 'xyz' 而非 true,只是 if 述句強制把 'xyz' 值轉型為一個 boolean
Symbol 的強制轉型
ES6 的 Symbol 為強制轉型系統引入了一個陷阱
var s1 = Symbol('hi');
非常少會遇到需要強制轉型一個 symbol