JavaScript 中类型转换及转换规则详解

类型转换表

转换为字符串 转换为数字 转换为布尔值 转换为对象
undefined “undefined” NaN false throw TypeError
null “null” 0 false throw TypeError
true “true” 1 new Boolean(“true”)
false “false” 0 new Boolean(“false”)
“” 0 false new String(“”)
“1.2” 1.2 true new String(“1.2”)
“1.2a” NaN true new String(“1.2a”)
“aaa” NaN true new String(“aaa”)
0 “0” false new Number(0)
-0 “0” false new Number(-0)
1 “1” true new Number(1)
NaN “NaN” false new Number(NaN)
Infinity “Infinity” true new Number(Infinity)
-Infinity “-Infinity” true new Number(-Infinity)
[] “” 0 true
[9] “9” 9 true
[“a”, “b”] “a,b” NaN true
{} 参见下 参见下 true
function() {} 参见下 NaN true

对象类型的转换

对象转换成字符( 这里说的是 String() 方法的原理 )

  1. 若对象具有 toString() 方法,调用 toString(),如果返回一个原始值,则将这个原始值转换为字符串返回。

  2. 若无 toString() 方法,或 toString() 的返回值并不是一个原始值,寻找其 valueOf() 方法,若存在这个方法,调用它,如果它返回一个原始值,将这个原始值转换为字符串返回。

  3. 若无 valueOf()valueOf() 的返回值不是原始值,则 JavaScript 无法得一个原始值,会抛出 throw TypeError

对象转换成数字(这里说的是 Number() 方法的原理)

  1. 若具有 valueOf() 方法,调用 valueOf(),如果它返回一个原始值,将这个原始值转换为数字返回。

  2. 若无 valueOf() 方法,或 valueOf() 的返回值并不是一个原始值,寻找其 toString() 方法,若存在这个方法,调用它,如果它返回一个原始值,将这个原始值转换为数字返回。

  3. 若无 toString()toString() 的返回值不是原始值,则 JavaScript 无法得一个原始值,会抛出 throw TypeError

1
1. 对象转字符串:先调用 toString() 再尝试调用 valueOf()。
2
2. 对象转数字: 先调用 valueOf() 再尝试调用 toString()。
3
3. 数组类型的转换也遵循以上三条,不过数组的 join() 方法的返回结果覆盖了原型链上的toString() 方法。

对象转换成布尔值

对象类型转换为布尔值:均为 true,不管其 toString()valueOf() 方法返回什么。

各类型的 toString()、valueOf() 方法的返回值

1. 对象

  • toString() 返回:*”[object Object]”*。
  • valueOf() 返回:对象本身

2. 数组

  • toString() 返回:arr.join() 的返回值
  • valueOf() 返回:数组本身

3. 函数

  • toString() 返回:整个函数字符串

  • valueOf() 返回:函数本身

    1
    function foo() {return "foo"};
    2
    foo.toString() // "function foo() {return "foo"}"
    3
    foo.valueOf() // ƒ foo() {return "foo"}

    4. 日期

  • toString() 返回:完整时间字符串

  • valueOf() 返回:从1970年1月1日0时0分0秒(UTC,即协调世界时)到该日期的毫秒数。

1
var date = new Date()
2
date.toString() // "Tue Nov 05 2019 13:54:57 GMT+0800 (中国标准时间)"
3
date.valueOf() // 1572933297576

5. Error

  • toString() 返回:*”Error: 错误描述”*。
  • valueOf() 返回:错误本身

6. RegExp

  • toString() 返回:正则式完整字符串
  • valueOf() 返回:正则本身
1
var a = new RegExp('^ass[^fsf]\w?','gi');
2
a.toString(); // "/^ass[^fsf]\w?/gi"
3
a.valueOf(); //  /^ass[^fsf]\w?/gi

运算符中的隐式类型转换

以上只是一些原理的介绍,下面介绍运算符中的隐式类型转换。

1.算术运算符(+、-、*、/、++、–、% …)

  • + 作为一个双目运算符: 若 + 两边存在一个字符串,将另一个也转为字符串进行字符串拼接。

  • 其他情况下,不管双目还是单目,都转为数值类型。

2. 关系运算符(>、<、==、!= …)

  • ===!==:同时对比类型和值,两个都为真才返回真。

  • ==!=: 若两边均为对象,对比它们的引用是否相同。

  • 逻辑非 !: 将其后变量或表达式转为布尔值。

  • 字符串比较:从头至尾扫描逐个比较每个字符的 unicode 码,直到分出大小。

  • 其他情况下,两边均转为数值类型。

注意

  1. NaN 与任何值都不相同,与任何值比较都返回 false

  2. 对象类型在运算时进行类型转换都先调用 valueOf() 方法,再尝试 toString() 方法。

  3. 在进行对象字面量运算时要注意,若运算符两边都是字面量,则将它们都视为对象字面量进行类型转换;若只有一个字面量时要注意,当这个字面量在首位时,会被当做一个块(表达式)看待。

1
{} + {} 		// "[object Object][object Object]"
2
[1,2,3] + [] 	//	 "1,2,3" + "" -> "1,2,3" 
3
[] + {} 		// "" + "[object Object]" -> "[object Object]"
4
{} + []		    // 0 -> {} 被当做一个块(表达式),相当于执行 ({},+[]),返回值为小括号最后面的表达式的返回值。
5
{q:1} + [] 		// 0
6
7
var a = {q:1};
8
a + []	 //  "[object Object]"     变量形式运算正常
9
[] + a 	 // "[object Object]"
10
11
{} == []  => 报错   ({}, ==[]) -> 报错
12
[] == 0   => true	[] -> "" -> 0
13
![] == 0  => true   ![] -> false -> 0
14
[] == ![] => true   [] -> "" -> 0    ![] -> false -> 0
15
[] == []  => false  比较引用地址
16
{} == {}  => false  比较引用地址
17
{} == !{} => false  !{} -> false -> 0    {} -> "[object Object]" -> NaN