字符串连接符和算数运算符

如果运算符两边都是原始类型(Primitive Values):

  • 不含字符串时,将非 Number 类型的值转换为 Number

    1
    2
    3
    4
    5
    1 + true                                        // => 2
    1 + undefined // => NaN
    1 + null // => 1
    null + true // => 1
    true + true // => 2
  • 含字符串时,+为字符串连接符,会将两侧的值转换为字符串类型

    1
    2
    3
    4
    5
    '1' + 1                                           // => '11'
    '1' + true // => '1true'
    '1' + undefined // => '1undefined'
    '1' + null // => '1null'
    '1' + NaN // => '1NaN'

需要注意的是,如果有多个值,+按从左到右运算

1
true + undefined + '2' + null                           // => 'NaN2null'

如果运算符两边有对象类型,会遵循对象到原始类型的转换规则,先调用对象的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
const obj1 = {
valueOf() {
return 2
}
}
console.log(1 + obj1) // => 3
----------------------------------------------------------------------------------
const obj2 = {
toString() {
return '{}'
}
}
console.log(1 + obj2) // => '1{}'
----------------------------------------------------------------------------------
const obj3 = {
valueOf() {
return '3'
},
toString() {
return 3
}
}
console.log(true + obj3) // => 'true3'

关系运算符

常见的需要进行类型转换的关系运算符有 ==、<、>、<=、>=,其转换规则为

  1. 如果两个操作数类型相同,对于引用类型除非指向地址相同否则不相等

  2. 如果有对象,按上述规则转换为原始类型(先 valueOf 后 toString)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    const obj = {
    valueOf() {
    return 2
    }
    }
    console.log(1 < obj) // => true
    --------------------------------------------------------------------------
    [] == 0 // => true
    // [].valueOf() => [], [].toString() => '', Number('') => 0
  3. 对于两个原始类型,如果为字符串,则按字母表顺序比较两个字符串

  4. 如果两个原始类型至少有一个不是字符串类型,则会调用Number()将操作数转换为数字类型后进行比较

    1
    2
    3
    2 > 10                                              // => false
    '2' > 10 // => false
    '2' > '10' // => true
  5. 特殊规则:如果转换后有一个数为NaN,则返回falseundefinednull也有特殊的规则

    1
    2
    3
    4
    5
    6
    undefined == false                                  // => false
    undefined < 1 // => false
    undefined == undefined // => true
    undefined == null // => true
    undefined === null // => false
    null == null // => true

逻辑运算符

使用逻辑运算符会调用Boolean()将操作数转换为布尔值,有且仅有false null undefined 0 -0 NaN''会被转换成fasle所有的对象类型,包括空对象,空数组和函数均为true

举几个例子

1
2
![] == []                                                  // => true
![] == 0 // => true

由于逻辑运算符优先级更高,空数组被转换成true,取反为false,右边的空数组也要转换成原始类型,调用其toString方法(valueOf返回数组本身,为对象)返回空字符串'',再将两边都转换为数字,因此![] == []转换后为0 == 0,得到true

1
2
3
4
Array.prototype.valueOf = function() {
return `[${this.join(',')}]`
}
console.log(![] == []) // => false
1
2
3
4
5
6
7
!{} == {}                                                    // => false
// Number({}.toString()) => Number('[object Object]') => NaN
----------------------------------------------------------------------------------------
const obj = {
toString: () => false
}
!obj == obj // => true

类型转换总结

原始类型

值(转换为) 字符串 数字 布尔值
undefined ‘undefined’ NaN false
null ‘null’ 0 false
true ‘true’ 1
false ‘false’ 0
‘’(空字符串) 0 false
‘1.2’ 1.2 true
‘one’ NaN true
0 ‘0’ false
-0 ‘0’ false
NaN ‘NaN’ false
Infinity ‘Infinity’ true
-Infinty ‘-Infinity’ true

规则

  • 对象转换为布尔值都是true,包括空数组、空对象、函数、包装器对象

  • 使用算术运算符时,操作数不含字符串,将非 Number 类型的值转换为 Number;含字符串时,+为字符串连接符,会将两侧的值转换为字符串类型

  • 使用关系运算符时,优先考虑将操作数转换成数字

  • 对象到原始类型的转换规则为:先调用对象的valueOf方法,如果不存在或者返回值的类型不是原始类型,则调用toString方法