在 JavaScript 中,值可以有不同的型別。你可以透過明確的_型別轉換_來改變變數的型別。除此之外,當情境需要時,JavaScript 也會執行_型別強制轉換_(隱性型別轉換)。
JavaScript 不像許多其他語言那樣有轉型成(其他)型別的語法,但你可以改用一些內建的輔助工具。其中最值得注意的是,全域物件 Boolean、Number 和 String 可以當作函式使用,把值轉換成對應的型別。
用 Boolean(value) 可以把任何值轉換成布林值。這是怎麼運作的呢?
有一組固定的值,也就是所謂的_假值_,會轉換成 false。最重要的是,false、0、空字串、null、undefined 和 NaN 都是假值。MDN 上關於「Falsy」的文章列出了完整的清單。
對於其他所有的值,Boolean 會回傳 true。這些值則稱為_真值_。
Boolean(-1);
// => true
Boolean(0);
// => false
Boolean(' ');
// => true
Boolean('');
// => false
請注意,根據上述規則,在 JavaScript 中 '0'、'false'、[] 和 {} 都是真值。
你可以用 Number(value) 把值轉換成數字。字串開頭和結尾的空白會被忽略,空字串則會轉換成 0。如果你試著轉換非原始型別的值,或是不代表數字的字串,不會拋出錯誤。結果會是 NaN(非數字)。
Number(' -12.34 ');
// => -12.34
Number('1,2');
// => NaN
Number('1 2');
// => NaN
Number('');
// => 0
Number('10e3');
// => 10000
Number({ key: '123' });
// => NaN
下面可以看到 Number 對其他原始型別的值會回傳什麼。
Number(true);
// => 1
Number(false);
// => 0
Number(null);
// => 0
Number(undefined);
// => NaN
請注意,和上一個例子不同,不帶任何引數呼叫 Number() 時,定義上會回傳 0。
JavaScript 也提供了 parseInt 和 parseFloat 這兩個函式。它們對於哪些字串可以轉換成數字,採用比較寬鬆的規則。因此,為了避免出乎意料的結果,最好優先使用 Number 做為轉換函式。
parseInt('123a45');
// => 123
Number('123a45');
// => NaN
用 String(value) 可以把值轉換成字串。對原始型別的值來說,結果就跟你想的一樣。
String(12.34);
// => '12.34'
String(false);
// => 'false'
String(null);
// => 'null'
String(undefined);
// => 'undefined'
對陣列來說,String 函式會對每個元素套用字串轉換,再用逗號把結果串接起來。你也可以自己套用 join 方法,例如自訂分隔符號。不過在這些情況下,null 和 undefined 會被轉換成空字串。
String([42, null, true, 'abc']);
// => '42,,true,abc'
對物件來說,String 預設會回傳一段沒什麼用的文字。
String({ key: 'value' });
// => '[object Object]'
你可以自訂轉換行為,例如提供一個 toString 方法。javascript.info 上的「Object to primitive conversion」一節說明了細節。
另一個常見的做法,是用 JSON 編碼 讓物件和陣列有更好的字串表示法。你可以用 JSON.stringify 轉換成字串,再用 JSON.parse 轉換回物件或陣列。
const obj = {
name: 'Gilda Guerra',
address: {
city: 'Goiânia',
},
};
JSON.stringify(obj);
// => '{"name":"Gilda Guerra","address":{"city":"Goiânia"}}'
在某些情境下,JavaScript 會在執行某個敘述之前,自動把值轉換成另一種資料型態。這種隱性轉換就叫做_型別強制轉換_。
當值用在布林情境中時,JavaScript 會套用和 Boolean 函式相同的規則,隱性地轉換這個值。
當 if 敘述 的條件不是布林值時,會套用強制轉換來判斷條件是否成立。三元運算子 ? 的第一個運算元也是如此。
const num = 0;
if (num) {
// this block is NOT executed because 0 is falsy
}
const name = 'Jin';
name ? 'name was provided' : 'no name provided';
// => 'name was provided'
邏輯 NOT 運算子 ! 的運算元,也會在套用 NOT 運算之前先被強制轉換成布林值。
const name = '';
!name;
// => true
這種行為的一個結果是,!!value 的效果和 Boolean(value) 相同。不過為了可讀性,你還是應該使用 Boolean。
JavaScript 也會對邏輯 AND(&&)和 OR(||)運算子的運算元套用強制轉換。但請記住,運算式的結果不一定是布林值。它會回傳其中一個原本的運算元(請參閱 MDN 上的邏輯運算子)。
null || 'hello';
// => 'hello'
如果加法運算子 + 用在原始型別的值上,而其中一個運算元是字串,另一個運算元也會被強制轉換成字串。轉換邏輯和使用 String 函式時相同。之後,這兩個字串會被串接起來。
let name;
'hello ' + name;
// => 'hello undefined'
嵌入 模板字串 中的非字串值,也會發生同樣的隱性轉換。
const degrees = 23;
`It is ${degrees} °C`;
// => 'Is is 23 °C.';
許多運算子會依照上面說明的 Number 函式邏輯,(在必要時)把運算元強制轉換成數字。
+(如果沒有牽涉到字串)、-、*、/、%、**
+、-
>、>=、<、<=
|、&、^、~
關於這些運算子的更多細節,請參閱 MDN 的運算子清單。
當運算元有可能是字串時,最好一律用 Number 函式明確轉換,以避免出錯。
'1' + '2';
// => '12'
// addition operator in string context as explained above
Number('1') + Number('2');
// => 3
有時候你會看到有人用一元加號運算子把字串強制轉換成數字。這並不推薦,因為它比明確呼叫 Number 難懂得多。
const value = '42';
+value;
// => 42
Number(value);
// => 42
使用寬鬆相等與不相等運算子 ==/!= 時,也常常牽涉到隱性的數字轉換。不過,這些運算子的確切邏輯相當複雜(請參閱 MDN 上的寬鬆相等)。結果難以預測,有時甚至和你想的不一樣。請改用嚴格相等/不相等運算子 ===/!==,以避免這些隱性轉換。