js操作符涉及的类型转换

328 阅读4分钟

加法操作符(+)

转换规则:

  • 如果两个数都是数值:

    • 如果有**任一操作数**是NaN,则返回NaN
    • 如果是Infinity-Infinity,则返回NaN.(若是一个操作数是Infinity/-Infinity.另一个数是有限或无限数(符号相同)都不影响Infinity/-Infinity)
  • 如果有一个操作数是字符串:

    • 如果两个操作数都是字符串,则将第二个字符串拼接到第一个字符串后面。
    • 如果只有一个操作数是字符串,则将另一个操作数转换为字符串(String()),再将两个字符串拼接在一起。
  • 如果操作数是布尔值,null,undefined:
    • 则先在后台使用Number()将其转换为数值。再执行前面的运算
  • 如果操作数是对象:
    • valueOf()则调用valueOf()。如果发现valueOf()转换后的值不能参与运算,则执行下一步
    • 调用toString().再执行上面字符串的相关规则

举个栗子:

// 两个数都是数值
NaN + 5 // NaN
Infinity + -Infinity // NaN
Infinity - 20 // Infinity
-Infinity + 20 // -Infinity
// 有一个数是字符串
5 + '5' // '55'
true + '' // 'true'
'20' + '21' // '2021'
// 操作数是undefined,null,布尔值
true + false // 0
true + 9 // 10
undefined + 5 // NaN
// 操作数是对象
[] + null // 'null' (数组的valueOf()返回[]不能参与+运算,调用toString()<返回数组每一项转为
// 字符串后的数组>; []数组则为'',此时,相当于 '' + null.所以值为'null')
[] + {} // '[object Object]' ( 相当于 '' + {}, {}调用valueOf()方法结果为{},不能参与运算,再执行toString()<'[object Object]'>.此时相当于 '' + '[object Object]')

特殊情况

表达式{} + []的值为多少呢?[object Object] ?

不是,值为0。为什么?

表达式中{}会被当成独立的空代码块(不执行任何操作)/* 代码块可理解?0.0 */。最后 + [][]显示强制转换为Number也就是0

知道原因了,那么怎么解决呢?

使用()包裹就行了。也就是 ({} + [])这样结果就是[object Object]

补充

let title, width;

{ title, width } = { title: 'menu', width: '80px' }

title, width结果是多少?

答案是会报错!很奇怪?

现代javascript教程:结构赋值。这里有解释~

减法操作符(-)

转换规则

  • 两个操作数是数值:
    • 如果任一操作数是NaN,则返回NaN
    • 对于Infinity/-Infinity同符号相减则为NaN.不同符号则不变(被减数)
  • **如果任一操作数是字符串布尔值nullundefined: **
    • 先在后台使用Number()将其转换为数值。再根据数值运算规则.
  • 如果任一操作数是对象:
    • 调用其valueOf()方法取得表示它的数值。再根据数值运算规则.
    • 如果没有valueOf(),则调用toString()。再将得到的字符串转换数值

举个栗子:

// 两个操作数都是数值
NaN - 5 // NaN
Infinity - Infinity // NaN
-Infinity - Infinity // -Infinity
// 任意操作数是....
5 - "" // 5
true - null // 1
5 - undefined // NaN
// 操作数是对象
[] - {} // NaN
[] - 5 // -5

关系操作符(>, <, <=, >=)

任何涉及NaN的比较都会返回false

转换规则:

  • 如果操作数是数值,则执行数值的比较。
  • 如果操作数都是字符串,则逐个比较字符串中对应字符的编码。// 请看清楚...
  • 如果任一操作数是数值,则将另一个操作数转换为数值,执行数值比较。
  • 如果任一操作数是对象,则调用其valueOf()方法。若是没有valueOf()则调用toString()方法。取得结果后在根据前面的规则执行比较。

举个栗子:

'23' < '3' // true 比较编码
'23' < 3 // false '23'会先转换为数值
'a' < 3 // false 'a'转换为数值为NaN
'a' >= 3 // false 同理
'Brick' < 'alphabet' // true 'a'的编码是97,‘B'的编码是66
[] < 3 // true []转换为0
[42] < ['43'] // true
['42'] < ['043'] // false 同为字符串则进行字符编码比较

特殊情况:

const a = { b: 42 }
const b = { b: 43 }

a < b // ? => false
a == b // false
a > b // ? => false

a <= b // ? => true
b <= a // ? => true

我们需要记住的是:javascript中,<=我们不应该理解为"小于或等于"。实际上<=是“不大于”的意思。即a <= b处理为!(a > b)>=同理

相等操作符( == )

转换规则:

  • 如果任一操作数是布尔值,则将其转换为数值再比较是否相等。
  • 如果一个操作数是字符串,另一个操作数是数值。则尝试将字符串转换为数值,再比较是否相等。
  • 如果一个操作数对象且另一个操作数不是,则调用对象的valueOf()方法取得其原始值,再根据前面的规则进行比较。

null == undefined

null undefined **不会转换为其他类型 **

NaN不等于任何包括它自己在内的任何数,也就是说若是存在NaN操作数,则立即返回false .(NaN != NaN // true )

操作数都为对象,则比较是否指向同一块内存地址

举个栗子:

true == 1 // true
'55' == 55 // true
[] == "" // true
true == [] // false 首先 true会转换为1。[]调用valueOf()后不能执行运算,继而调用toString()转换为"",再将""转换为数值0
null == 0 // false 注意了:虽然null可以转换为0,但是在执行 == 操作时, null是不会进行转换的
[] == ![] // true 
// 不理解?(小声bb: 真离谱...)首先会将右边的![]执行,值为false,
// 此时相当于[] == false。再应用第一条规则,即[] == 0,此时 []经过转换为“”, 再应用第二条规则,
// 即 0 == 0 所以为true
2 == [2] // true 
// 还记得数组的toString么,若是数组存在多项则转换为以','分隔的字符串。相当于str.split(',')
// [2]被转换为'2',再转换为2

参考资料

  • javascript高级程序设计(第四版)
  • 你不知道的javascript(中)