0%

JS中的类型转换

简单总结一下JS中的部分显/隐式强制类型转换。

1、类型

JS中6种基本类型:

Undefined, Null, Boolean, Number, Symbol, or String

以及对象:

member of the type Object

Boolean的真假值

其他类型转换为Boolean类型时,一般遵从下面的表值映射:

Undefined Return false.
Null Return false.
Boolean Return argument.
Number If argument is +0, -0, or NaN, return false; otherwise return true.
String If argument is the empty String (its length is zero), return false; otherwise return true.
Symbol Return true.
Object Return true

通过!操作符转换为Boolean类型。

&&||操作符在表达式中会把值强制转换为Boolean类型。

但是&&||操作符返回的不是布尔值。

2、转换为数字、字符串

0.Null/Boolean/Undefined/Symbol => 字符串/数字

以下列举了几种Null/Boolean/Undefined/Symbol类型转换为数字类型的情况:

  • Null值:=>字符串'null',=>数字0
  • Boolean值:truefalse,转换为字符串分别是:'true''false';转换为数字分别是10
  • undefined值:=>字符串'undefined',=>数字NaN
  • Symbol值无法被转换为字符串/数字

1.字符串=>数字

以下列举了几种字符串类型转换为数字类型的情况:

  • +-操作符 + 字符串,发生强制类型转换
  • 字符串 + 操作符 + 数字,发生强制类型转换
  • 调用Number
  • 调用parseInt
  • 使用==操作符时

具体的转换情境如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
let num;
// 1. 使用'-','+'
num = -'str' // NaN
num = -'1234' //1234
num = '1234' - 1; // 1233
num = 'asd1234' - 1; // NaN
num = '1e10' // 10000000000
num = '1234.5' // 1234.5
num = '' // 0
// 2. 调用Number

num = new Number('1234').valueOf(); // 1234
num = new Number('1e10').valueOf(); // 10000000000
num = new Number('s1234').valueOf(); //NaN

// 3. 调用parseInt parseInt(s, ?radix),radix为进制

num = parseInt('s1234'); // NaN
num = parseInt('1234.3s'); // 1234
num = parseInt(1 / 0, 19); // 18 1 / 0 === Infinity => ToString => 'Infinity' => 进制为19,0~i,i恰好为最后一位,所以结果为18

总的来说:

  • -操作符和调用Number的方式差不多,字符串中出现0~9以外的值,例如字母等,不论位置,都会返回NaN的结果。
  • parseInt第一个参数是字符串,如果不是,会先转换为字符串再进行求值。与1和2的方式不同,parseInt会解析字符串中非数字在数字后面的字符串,如’1234.3ssss’,返回1234。
    值得注意的是,空字符串会转换为数字0。

2.Object=>数字/字符串

Object转换为数字/字符串会进行ToPrimitive抽象操作,而且顺序一般是valueOftoString,如果valueOf方法返回基本类型值,就使用该返回值,否则就调用toString

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// 1.valueOf返回非基本类型值,toString返回1,
let o = {

}
+o // NaN
o + '' // [object Object]

o = {
toString: function toString(){
return 1
}
}
+o // 1
o + '' // '1'

// 2.valueOf返回2
o = {
valueOf: function valueOf(){
return 2
}
}
+o // 2
o + '' // '2' valueOf返回数字2,数字2再转换为字符串'2'

// 3.valueOf和toString
o = {
valueOf: function valueOf(){
return 2
},
toString: function toString(){
return 1
}
}
+o // 2
o + '' // '2'

3.ToPrimitive抽象操作

占坑

3、使用==时发生的类型转换

执行x == y

  1. xy类型相同,则返回 x===y的结果。
  2. 如果xy任意一方为undefined,另一方为null则返回true
  3. 如果xy有一方为字符串/布尔值,则为字符串/布尔值的一方执行ToNumber的抽象操作,转换为数字。
  4. 如果xy有一方为对象(包括数组、包装对象等子对象),则为对象一方执行ToPrimitive抽象操作。

以上参考自如下的ES10标准:

The comparison x == y, where x and y are values, produces true or false. Such a comparison is performed as follows:

  1. If Type(x) is the same as Type(y), then
    a. Return the result of performing Strict Equality Comparison x === y.
  2. If x is null and y is undefined, return true.
  3. If x is undefined and y is null, return true.
  4. If Type(x) is Number and Type(y) is String, return the result of the comparison x == ! ToNumber(y).
  5. If Type(x) is String and Type(y) is Number, return the result of the comparison ! ToNumber(x) == y.
  6. If Type(x) is Boolean, return the result of the comparison ! ToNumber(x) == y.
  7. If Type(y) is Boolean, return the result of the comparison x == ! ToNumber(y).
  8. If Type(x) is either String, Number, or Symbol and Type(y) is Object, return the result of the comparison x ==
    ToPrimitive(y).
  9. If Type(x) is Object and Type(y) is either String, Number, or Symbol, return the result of the comparison
    ToPrimitive(x) == y.
  10. Return false.
    The comparison x === y, where x and y are values, produces true or false. Such a comparison is performed as follows:
  11. If Type(x) is different from Type(y), return false.
  12. If Type(x) is Number, then
    a. If x is NaN, return false.
    b. If y is NaN, return false.
    c. If x is the same Number value as y, return true.
    d. If x is +0 and y is -0, return true.
    e. If x is -0 and y is +0, return true.
    f. Return false.
  13. Return SameValueNonNumber(x, y).
    NOTE
    This algorithm differs from the SameValue Algorithm in its treatment of signed zeroes and NaNs.

从规范中可以看出,如果检测到双方类型相等,则会进行全等比较;否则,在进行相等比较的过程中,会进行abstract operation,即:ToNumberToPrimitive转换类型进行比较,最终比较的是两边的数字。

ToNumber即转换为数字类型,上文说明了转换的情景。

对象进行ToPrimitive操作,一般会调用valueOftoString方法。故可以通过改写valueOftoString方法使ToPrimitive返回特定值。

参考

  1. 你不知道的JS(中)
  2. ECMA-262