徹底理解JavaScript中的類型轉(zhuǎn)換

1. 什么是類型轉(zhuǎn)換?
Javascript 是一種弱類型語言,這意味著變量是沒有明確類型的,而是由 JavaScript 引擎在編譯時隱式完成。類型轉(zhuǎn)換就是將一種數(shù)據(jù)類型轉(zhuǎn)換為另一種數(shù)據(jù)類型,例如:

20 + "twenty" // "20twenty"
"10" * "10"   //  100
2 - "x"
Javascript 使用嚴格相等(===)和寬松相等(==)來測試兩個值的相等性,類型轉(zhuǎn)換僅在使用寬松相等運算符時發(fā)生。當使用 === 測試嚴格相等時,要比較的變量的類型和值都必須相同,例如:

10 === 10     // true
NaN === NaN   // false
在上面的代碼中,10和10都是數(shù)字并且是完全相等的,所以正如預期的那樣返回了true,兩個 NaN 永遠不會相等。當使用 == 測試寬松相等時,可能會發(fā)生隱式轉(zhuǎn)換:

'20' == 20    // true
false == 0    // true
對于任何數(shù)據(jù)類型,無論是原始類型還是對象,都可以進行類型轉(zhuǎn)換。盡管原始類型和對象的轉(zhuǎn)換邏輯各不相同,但是都只能轉(zhuǎn)換為三種類型:字符串(string)、數(shù)字(number)、布爾值(boolean)。

JavaScript 中的類型轉(zhuǎn)換有兩種方式:

隱式類型轉(zhuǎn)換: 由 JavaScript 編譯器完成的自動類型轉(zhuǎn)換。
顯式類型轉(zhuǎn)換: 由開發(fā)人員完成的手動類型轉(zhuǎn)換。
下面先來看看 JavaScript 中的顯式和隱式類型轉(zhuǎn)換。

(1)顯示類型轉(zhuǎn)換
我們可以通過 JavaScript 內(nèi)置的一些 API 將一種類型轉(zhuǎn)換為另一種類型,這稱為顯式類型轉(zhuǎn)化。執(zhí)行顯式類型轉(zhuǎn)換的最簡單方法是使用 Boolean()、Number() 和 String()、parseInt()等函數(shù),例如:

String(2 - true);     // '1'
'56' === String(56);  // true
Number('2350e-2');    // '23.5'
Number('23') + 7;     // 30
Boolean('');          // false
Boolean(2) === true;  //true
(2)隱式類型轉(zhuǎn)換
隱式類型轉(zhuǎn)換是將一種數(shù)據(jù)類型轉(zhuǎn)換為另一種數(shù)據(jù)類型(確保在相同數(shù)據(jù)類型之間完成操作)以使運算符或函數(shù)正常工作,這種轉(zhuǎn)換是由 JavaScript 編譯器自動完成的,隱式類型轉(zhuǎn)換也稱為類型強制。例如:

'25' + 15;          // '2515'
23 * '2';           // 46
23 - true;          // 22
true - null;        // 1
false + undefined;  // NaN

const arr = [];
if(arr) { console.log('Hello World') };
下面這些常見的操作會觸發(fā)隱式地類型轉(zhuǎn)換,編寫代碼時要格外注意:

運算相關的操作符:+、-、+=、++、* 、/、%、<<、& 等。
數(shù)據(jù)比較相關的操作符: >、<、== 、<=、>=、===。
邏輯判斷相關的操作符: &&、!、||、三目運算符。
① + 運算符
/* 一個操作數(shù) */
+ x // 將x轉(zhuǎn)化為數(shù)字, 如果不能轉(zhuǎn)化為數(shù)組將輸出NaN
+ "1234string"   // NaN
+ 1              // 1
+ '1'            // 1
+ true           // 1
+ undefined      // NaN
+ null           // 0
+ new Date()     // 1660493819396

/* 兩個操作數(shù) */
a + b

// 1. 如果其中任何一個是對象,則先將其轉(zhuǎn)換為原始類型
{} + {}          // '[object Object][object Object]'
[] + []          // ''
[] + new Date()  // 'Mon Aug 15 2022 00:18:18 GMT+0800 (中國標準時間)'

// 2. 如果一個是字符串,則將另一個轉(zhuǎn)換為字符串
1 + ''           // '1'
'' + 1           // '1'
'' + true        // 'true'

// 3. 否則,將兩者都轉(zhuǎn)換為數(shù)字
1 + true         // 2
true + true      // 2
② -、*、/、++、--
// 將一個或多個值轉(zhuǎn)換為數(shù)字
 - '1'     // -1
 [] - 1    // -1
 [] - {}   // NaN
③ ==、!=
// 兩個操作數(shù)
 a == b

// 1. 如果一個是 `null` 而另一個是 `undefined`,它們是相等的
null == undefined    // true

// 2. 如果一個是數(shù)字,另一個是字符串,將字符串轉(zhuǎn)換為數(shù)字,再比較
1 == '1'             // true

// 3. 如果其中一個是布爾值,將其轉(zhuǎn)換為數(shù)字,再次比較
true == 1            // true
false == 0           // true

// 4. 如果一個是對象,另一個是數(shù)字或字符串,將對象轉(zhuǎn)換為原始類型,再次比較
[1] == 1             // true
['1'] == '1'         // true
下圖是在使用 == 時,判斷兩個操作數(shù)是否相等的總結(jié)(綠色表示相等,白色表示不等):



④ >、>=、<、<=
// 兩個操作數(shù)
a > b

// 1. 如果其中一個是對象,則將其轉(zhuǎn)換為原始類型,再次比較
[2] > 1   // true

// 2. 如果兩者都是字符串,使用字母順序比較它們
'b' > 'a' // true

// 3. 如果其中一個是數(shù)字,則將一個或兩個非數(shù)字轉(zhuǎn)換為數(shù)字
'2' > 1   // true
⑤ in
/* 如果左操作數(shù)不是字符串,則將其轉(zhuǎn)換為字符串 */
 a in b

'1' in {1: ''}    // true
 1 in {1: 'a'}    // true
 1 in ['a', 'b']  // true
2. 常見類型轉(zhuǎn)換
(1)字符串轉(zhuǎn)換
將數(shù)據(jù)類型轉(zhuǎn)換為字符串稱為字符串轉(zhuǎn)換,可以使用 String() 函數(shù)將數(shù)據(jù)類型顯式轉(zhuǎn)換為字符串。當一個操作數(shù)是字符串時,可以通過使用 + 運算符來觸發(fā)隱式字符串轉(zhuǎn)換。

① 數(shù)字 => 字符串:
Number對象的 toString() 方法會返回指定 Number 對象的字符串表示形式。String()和 new String() 會把對象的值轉(zhuǎn)換為字符串。

String(20);           // '20'
String(10 + 40);      // '50'
(10 + 40).toString(); // '50'
new String(10 + 20);  // '30'
② 布爾值 => 字符串:
String() 和 toString() 方法會將布爾值轉(zhuǎn)化為對應的字符串形式。

String(true);     // 'true'
String(false);    // 'false'
true.toString()   // 'true'
false.toString()  // "false"
③ 數(shù)組 => 字符串:
String() 方法會將數(shù)組元素通過逗號連接起來,無論嵌套多少層,都會將其展開并返回元素拼接好的字符串。如果是空數(shù)字,會返回空字符串:

String([1, 2, 3]);                // '1,2,3'
String([1, 2, 3, [4, [5]]]);      // '1,2,3,4,5'
String([1, 2, 3, [4, [5, {}]]]);  // '1,2,3,4,5,[object Object]'
String([]);                       // ''
④ 對象 => 字符串:
使用 String() 方法會將對象轉(zhuǎn)化為 '[object Object]',無論對象是否為空對象:

String({name: "Hello"});   // '[object Object]'
⑤ null / undefined / NaN => 字符串:
使用 String() 方法會將  null、undefined、NaN 轉(zhuǎn)化為其對應的字符串形式:

String(undefined);    // 'undefined'
String(null);         // 'null'
String(NaN);          // 'NaN'
⑥ 日期 => 字符串:
String(new Date('2022-08-20')) // 'Sat Aug 20 2022 08:00:00 GMT+0800 (中國標準時間)'
⑦ 隱式轉(zhuǎn)換
當任何數(shù)據(jù)類型使用+運算符與字符串連接時會發(fā)生到字符串的轉(zhuǎn)換(隱式轉(zhuǎn)換):

"25" + 56;              // '2556'
"25" + null;            // '25null'
"Hello " + undefined;   // 'Hello undefined'
"25" + false;           // '25fasle'
"25" + {};              // '25[object Object]'
"25" + [10];            // '2510'
所以,當我們想要創(chuàng)建一個操作并且操作數(shù)類型之一是字符串時,應該小心使用類型強制轉(zhuǎn)換。

⑧ 總結(jié)
下面是 ECMAScript 規(guī)范中將數(shù)據(jù)類型轉(zhuǎn)換為字符串的規(guī)則:



ECMAScript 規(guī)范:https://262.ecma-international.org/5.1/#sec-9.8






(2)布爾轉(zhuǎn)換
將數(shù)據(jù)類型轉(zhuǎn)換為布爾值稱為布爾轉(zhuǎn)換。這種轉(zhuǎn)換既可以由 Boolean() 函數(shù)顯式完成,也可以在邏輯上下文中隱式完成(如if/else )或通過使用邏輯運算符( ||、&&、! )觸發(fā)。

① 字符串 => 布爾值:
使用 Boolean() 方法轉(zhuǎn)化字符串時,只有當字符串為空時會返回false,其他情況都會返回 true:

Boolean('hello'); // true
Boolean(' ');     // true
Boolean('');      // false
② 數(shù)字 => 布爾值:
使用 Boolean() 方法轉(zhuǎn)化數(shù)字時,只有 0、-0 或 NaN 會轉(zhuǎn)化為 false,其他情況會返回 true:

Boolean(-123); // true
Boolean(123);  // true
Boolean(0);    // false
Boolean(-0);   // false
Boolean(NaN);  // false
③ 數(shù)組 / 對象 => 布爾值:
使用 Boolean() 方法轉(zhuǎn)化數(shù)組或?qū)ο髸r,無論數(shù)組和對象是否有內(nèi)容,都會返回true:

Boolean([1, 2, 3]); // true
Boolean([]);        // true
Boolean({});  // true
Boolean({'hello': 'world'});  // true
④ null / undefined => 布爾值:
使用 Boolean() 方法轉(zhuǎn)化null或undefined時,都始終返回 false:

Boolean(undefined);  // false
Boolean(null);       // false
⑤ 隱式轉(zhuǎn)換
在數(shù)學運算中,true 轉(zhuǎn)換為 1,false 轉(zhuǎn)換為 0:

true + 5;    // 6
false + 5;   // 5
5 - true;    // 5
5 - false;   // 4
⑥ 邏輯運算符、邏輯上下文
// 如果其中一個不是布爾值,則將其轉(zhuǎn)換為布爾值
Boolean( null || undefined || 0 || -0 || NaN || '' )    // false
Boolean( 1 && 'a' && { } && [] && [0] && function(){} ) // true
true && false // false
true && true // true
true || false // true
true || !false // true
注意,邏輯運算符,例如 || 或 && 內(nèi)部進行布爾轉(zhuǎn)換,但實際上返回原始操作數(shù)的值,即使它們不是布爾值。

'hello' && 123;   // 123
可以使用雙感嘆號(!!)來將變量轉(zhuǎn)為為布爾值:

!!0    // false
!!""   // false
!!" "  // true
!!{}   // true
!![]   // true
!!true // true
if、else if、while、do/while 和 for 使用與 &&、||、! 相同的隱式類型轉(zhuǎn)換方式(邏輯表達式)。

下面是在 if 語句(邏輯上下文)中的隱式轉(zhuǎn)換規(guī)則(綠色為true,白色為false):



⑦ 總結(jié)
除了下面這些之外的所有其他值都是真值,包括對象、數(shù)組、日期等。甚至所有Symbol、空對象和數(shù)組都是真值。

Boolean('');        // false
Boolean(0);         // false     
Boolean(-0);        // false
Boolean(NaN);       // false
Boolean(null);      // false
Boolean(undefined); // false
Boolean(false);     // false
Boolean({})             // true
Boolean([])             // true
Boolean(Symbol())       // true
Boolean(function() {})  // true
可以通過以下方式來過濾數(shù)組中的假值:

[0, "", " ", null, undefined, NaN].map(Boolean);
// 輸出結(jié)果:[false, false, true, false, false, false]
我們可以會遇到一種情況,當使用 5 == true 時,結(jié)果為false,而使用if(5) {}時,則 5 被認為是 true 并進入if/else語句:

5 == true;  // false

if (5) {
    console.log('5');  // 5
};
這種情況下,即一個值和數(shù)字進行比較時,JavaScript 會試圖將這個值轉(zhuǎn)換為數(shù)字。所以,當比較5 == true 時,JavaScript 傾向于將true轉(zhuǎn)換為1,因為 1不等于5,因此結(jié)果為 false。而在if(5) {}的情況下,5 被轉(zhuǎn)換為布爾值,而 5 是一個真值,所以它進入if塊。在這種情況下,可以選擇顯式轉(zhuǎn)換以避免錯誤,因為 5 是一個真值,可以執(zhí)行Boolean(5) == true,這樣就會返回true了。

下面是 ECMAScript 規(guī)范中將數(shù)據(jù)類型轉(zhuǎn)換為布爾值的規(guī)則:



ECMAScript 規(guī)范:https://262.ecma-international.org/5.1/#sec-9.2

(3)數(shù)字轉(zhuǎn)換
將數(shù)據(jù)類型轉(zhuǎn)換為數(shù)字稱為數(shù)字轉(zhuǎn)換,可以使用Number()、parseInt()、parseFloat()等方法將數(shù)據(jù)類型顯式轉(zhuǎn)換為數(shù)字。當一個值不能被強制轉(zhuǎn)換為一個數(shù)字時,就會返回 NaN。

① 字符串 => 數(shù)字:
當把字符串轉(zhuǎn)換為數(shù)字時,JavaScript 引擎首先會修剪前導和后置空格、\n、\t 字符,如果修剪后的字符串不代表有效數(shù)字,則返回 NaN。 如果字符串為空,則返回 0。

Number('123');            // 123
Number("-12.34")          // -12.34
Number("12s");            // NaN
Number("\n")              // 0

parseInt(' 203px');       // 203
parseInt('10.000')        // 10   
parseInt('10.20')         // 10
parseFloat('203.212px');  // 203.212
parseFloat('10.20')       // 10.2
parseFloat('10.81')       // 10.81
可以看到,parseInt 函數(shù)會從字符串中讀取一個數(shù)字并刪除它后面所有字符,但是如果數(shù)字前面有字符(空格除外),那么它將輸出 NaN。

② 布爾值 => 數(shù)字:
當使用 Number() 將布爾值轉(zhuǎn)化為數(shù)字時,true 會轉(zhuǎn)化為 1,false 會轉(zhuǎn)化為 0。

Number(true);  // 1
Number(false); // 0
③ null  => 數(shù)字:
當使用 Number() 將 null 轉(zhuǎn)化為數(shù)字時,會返回 0:

Number(null); // 0
null + 5; // 5
④ undefined / 數(shù)組 / 對象 / NaN => 數(shù)字:
當使用 Number() 將 undefined、數(shù)組、對象、NaN 轉(zhuǎn)化為數(shù)字時,會返回 NaN:

Number(undefined);  // NaN
Number([1, 2, 3])   // NaN
Number({})          // NaN
Number(NaN)         // NaN
⑤ 數(shù)組元素
可以使用map遍歷數(shù)組元素,并使用需要的類型來進行類型轉(zhuǎn)換:

["1", "9", "-9", "0.003", "yes"].map(Number);
// 輸出結(jié)果:[1, 9, -9, 0.003, NaN]
⑥ 特殊規(guī)則
在表達式中,當我們將 == 運算符應用于 null 或 undefined 時,不會發(fā)生數(shù)字轉(zhuǎn)換。 此外,null 只等于 null 或 undefined,不能等于其他任何值:

null == null;           // true
null == 0;              // false
null == undefined;      // true
undefined == undefined  // true
根據(jù)運算符優(yōu)先級,+ 運算符具有從左到右的關聯(lián)性,因此如果有一個表達式 2 + 3 + '4' + 'number' ,則操作按以下方式完成:

2 + 3 + '4' + 'number'
==> 5 + '4' + 'number'
// 數(shù)字 5 被隱式轉(zhuǎn)換為字符串,然后連接起來
==> '54' + 'number'
==> '54number'
NaN 不等于任何其他類型,甚至它本身:

NaN == NaN  // false
⑦ 總結(jié)
上面的例子中,可以清楚地看到一些意想不到的結(jié)果:將 null 轉(zhuǎn)換為數(shù)字時返回了 0,而將 undefined 轉(zhuǎn)換為數(shù)字返回了 NaN。兩個操作都應該返回 NaN,因為這兩種值類型顯然都不是有效的數(shù)字,將空字符串轉(zhuǎn)換為數(shù)字時也返回了 0。

下面是 ECMAScript 規(guī)范中將數(shù)據(jù)類型轉(zhuǎn)換為字符串的規(guī)則,清楚的解釋了上面的異?,F(xiàn)象:








另外,在 ECMAScript 規(guī)范中,還提到一點:



意思就是:為空或僅包含空格的 StringNumericLiteral 將轉(zhuǎn)換為 +0。這也就解釋了為什么將空字符串轉(zhuǎn)換為數(shù)字時也返回了 0。

ECMAScript 規(guī)范:https://262.ecma-international.org/5.1/#sec-9.3

3. Symbol 類型轉(zhuǎn)換
Symbol  只能進行顯式轉(zhuǎn)換,不能進行隱式轉(zhuǎn)換。也就是說,Symbol不能被強制轉(zhuǎn)換為字符串或數(shù)字,這樣它們就不會被意外地用作本來應該表現(xiàn)為 Symbol 的屬性。

const mySymbol = Symbol.for("mySymbol");
const str = String(mySymbol);

console.log(str);  // 'Symbol(mySymbol)'

當使用 console.log() 來打印 symbol 時,它之所以有效,是因為 console.log() 在 symbol 上調(diào)用了 String() 方法以創(chuàng)建可用的結(jié)果。

如果嘗試直接使用字符串連接 symbol,它將拋出TypeError:

const mySymbol = Symbol.for("mySymbol");
const sum = mySymbol + "";
console.log(sum);   // Uncaught TypeError: Cannot convert a Symbol value to a string
將 mySymbol 連接到字符串需要首先將 mySymbol 轉(zhuǎn)換為字符串,并且在檢測到強制轉(zhuǎn)換時會拋出錯誤,從而阻止以這種方式使用它。

同樣,我們不能將 symbol 強制轉(zhuǎn)換為數(shù)字,所有數(shù)學運算符在與符號一起使用時都會引發(fā)錯誤:

const mySymbol = Symbol.for("mySymbol");
const factor = mySymbol / 2;
console.log(factor);   // Uncaught TypeError: Cannot convert a Symbol value to a number
4. 對象類型轉(zhuǎn)換
介紹完了基本數(shù)組類型的轉(zhuǎn)化,下面來看看對象類型的轉(zhuǎn)化。例如,當執(zhí)行 obj_1 + obj_2 或者 obj_1 - obj_2時,都會先將對象轉(zhuǎn)換為原始類型,然后將其轉(zhuǎn)換為最終類型。當然,這里的轉(zhuǎn)化仍然只有三種類型:數(shù)字、字符串和布爾值。

對象通過內(nèi)部的 ToPrimitive 方法將其轉(zhuǎn)換為原始類型,該算法允許我們根據(jù)使用對象的上下文來選擇應如何轉(zhuǎn)換對象。從概念上講,ToPrimitive 算法可以分為兩部分:Hints 和 Object-to-primitive 轉(zhuǎn)換方法。



(1)Hints
Hints 是 ToPrimitive 算法用于確定對象在特定上下文中應轉(zhuǎn)換為什么的信號。有三種情況:

string:在操作需要字符串的上下文中,如果可以轉(zhuǎn)換為字符串,例如 alert() 或內(nèi)置 String() 函數(shù):
alert(obj);
String(obj)

// 使用對象作為屬性key值
anotherObj[obj] = 1000;
number:如果可以進行這種轉(zhuǎn)換,則在操作需要數(shù)字的上下文中:
// 顯示轉(zhuǎn)換
let num = Number(obj);

// 數(shù)學(二進制加號除外)
let x = +obj; // 一元加
let difference = Date1 - Date2; // 日期對象

// 對象大小比較
let less = Obj1 < obj2;
default:在極少數(shù)情況下發(fā)生,不確定需要什么類型。例如,二元 + 運算符既適用于字符串(連接它們)也適用于數(shù)字(添加它們)。在這種情況下,對象可以轉(zhuǎn)換為字符串或數(shù)字。 或者當使用寬松相等 == 運算符將對象與字符串、數(shù)字或 symbol 進行比較時。
// 二元加
let sum = obj1 + obj2;

// obj == string/number/symbol
if (obj == 10 ) { ... };
所有內(nèi)置對象(日期除外)都將default認為是number,Date 日期對象將default認為是string。

(2)Methods
在 ToPrimitive 算法根據(jù) Hints 確定對象應轉(zhuǎn)換為的原始值類型之后。 然后使用 Object-to-primitive 轉(zhuǎn)換方法將對象轉(zhuǎn)換為原始值。有三種情況:

toString/valueOf:toString() 和 valueOf() 被 JavaScript 中的所有對象繼承。 它們僅用于對象到原始值的轉(zhuǎn)換。 ToPrimitive 算法首先會嘗試 toString() 方法。 如果定義了方法,它返回一個原始值,那么 JavaScript 使用原始值(即使它不是字符串)。 如果toString() 返回一個對象或不存在,那么 JavaScript 會嘗試使用 valueOf() 方法,如果該方法存在并返回一個原始值,JavaScript 將使用該值。 否則,轉(zhuǎn)換失敗并提示 TypeError。
toString -> valueOf:用于 Hints 為string 的情況。
valueOf -> toString:其他情況。
let Person = {
  name: "Mary",
  age: 22,

  // hint 是 "string"
  toString() {
    return `{name: "${this.name}"}`;
  },

  // hint 是 "number" 或 "default"
  valueOf() {
    return this.age;
  }
};

alert(Person);      // toString -> {name: "Mary"}
alert(+Person);     // valueOf -> 22
alert(Person + 10); // valueOf -> 32
在上面的代碼中,Person 變成了一個對象字符串或數(shù)字,具體取決于轉(zhuǎn)換上下文。 toString() 方法用于 Hints = "string" 的轉(zhuǎn)換,valueOf() 用于其他情況(Hints 為“number”或“default”)。

你可能希望在一個地方處理所有轉(zhuǎn)換。 在這種情況下,只能像這樣實現(xiàn) toString() 方法:

let Person = {
  name: "Mary",

  toString() {
    return this.name;
  }
};

alert(Person); // toString -> Mary
alert(Person + 1000); // toString -> Mary1000
Symbol.toPrimitive:與 toString() 和 valueOf() 方法不同,Symbol.toPrimitive 允許覆蓋 JavaScript 中的默認對象到原始值的轉(zhuǎn)換(其中 toString() 和 valueOf 方法由 ToPrimitive 算法使用)并定義我們希望如何將對象轉(zhuǎn)換為原始類型的值。 為此,需要使用此 Symbol 名稱定義一個方法,如下所示:

obj[Symbol.toPrimitive] = function(hint) {
  // 返回原始類型值
  // hint 等于 "string", "number", "default" 中的一個
}
例如,這里的 Person 對象使用 Symbol.toPrimitive 執(zhí)行與上面相同的操作:

let Person = {
  name: "Mary",
  age: 22,

  [Symbol.toPrimitive](hint) {
    alert(`hint: ${hint}`);
    return hint == "string" ? `{name: "${this.name}"}` : this.age;
  }
};

alert(Person);       // hint: string -> {name: "Mary"}
alert(+Person);      // hint: number -> 22
alert(Person + 10);  // hint: default -> 32
可以看到,單個方法 Person[Symbol.toPrimitive] 處理了所有轉(zhuǎn)換情況。需要注意,在沒有 Symbol.toPrimitive 和 valueOf() 的情況下,toString() 將處理所有原始類型轉(zhuǎn)換。

下面是將對象轉(zhuǎn)化為布爾值、字符串、數(shù)字時的執(zhí)行過程:

(1)對象到布爾值的轉(zhuǎn)換

Javascript 中的所有對象都轉(zhuǎn)換為 true,包括包裝對象 new Boolean(false) 和空數(shù)組。 對象到布爾值的轉(zhuǎn)換不需要對象到原始類型算法。

(2)對象到字符串的轉(zhuǎn)換

當需要將對象轉(zhuǎn)換為字符串時,Javascript 首先使用 ToPrimitive 算法(Hints = “string”)將其轉(zhuǎn)換為原始類型,然后將派生的原始類型轉(zhuǎn)換為字符串。例如,如果將對象傳遞給 String() 這樣的內(nèi)置函數(shù),或者在模板字符串中插入對象時。

(3)對象到數(shù)字的轉(zhuǎn)換

當需要將對象轉(zhuǎn)換為數(shù)字時,Javascript 首先使用  ToPrimitive  算法(Hints = “number”)將其轉(zhuǎn)換為原始類型,然后將派生的原始類型轉(zhuǎn)換為數(shù)字。 期望數(shù)字參數(shù)的內(nèi)置 Javascript 函數(shù)和方法以這種方式將對象參數(shù)轉(zhuǎn)換為數(shù)字,例如 Math()。

(3)特殊情況
當某些 Javascript 運算符的操作數(shù)是對象時,也會發(fā)生類型轉(zhuǎn)換:

+ 運算符: 此運算符可以用于執(zhí)行數(shù)字加法和字符串連接。如果其中任何一個操作數(shù)是對象,則使用  ToPrimitive 算法(Hints = “default”)將它們轉(zhuǎn)換為原始值。一旦將它們轉(zhuǎn)換為原始值,就會檢查它們的類型。如果任一參數(shù)是字符串,則將另一個參數(shù)轉(zhuǎn)換為字符串并連接字符串。否則,它將兩個參數(shù)都轉(zhuǎn)換為數(shù)字并將它們相加。
== 和 !== 運算符: 這些運算符以寬松方式執(zhí)行相等和不相等測試。如果一個操作數(shù)是一個對象而另一個是一個原始值,這些運算符使用  ToPrimitive  算法(Hints = “default”)將對象轉(zhuǎn)換為原始值,然后比較兩個原始值。
<,<=,> 和 >= 關系運算符: 關系運算符用于比較兩個值之間的關系,可用于比較數(shù)字和字符串。如果任一操作數(shù)是對象,則使用 ToPrimitive 算法將其轉(zhuǎn)換為原始值(Hints = “number”)。但是,與對象到數(shù)字的轉(zhuǎn)換不同,返回的原始值不會轉(zhuǎn)換為數(shù)字(因為它們被比較并且不被使用)。
參考文章:

https://blog.openreplay.com/javascript-type-conversions-explained
https://blog.logrocket.com/type-coercion-in-javascript/

作者:GUOZE


歡迎關注微信公眾號 :前端充電寶