JS 中隐式转换与'+'运算符常见场景(对象的转换)

320 阅读3分钟

请回答下列问题

  • [] == false
  • ![] == false
  • 'true' == ['true']
  • true == ['true']
  • {} + []
  • [] + {}
  • [] + []

隐式转换

== 比较运算

== 是隐式转换的常见场景之一,了解它可以解决许多笔试中不应该出错的问题。比如解决[] == false![] == false为什么都为true.

首先,什么时候会触发隐式转换,在 == 中,当两种数据类型不一样时,就会触发隐式转换

我总结了一个简单的转换规则:在 == 两边如果有对象,对象会先转换为字符串,如果此时数据类型还是不一样,字符串和布尔值再会转换为number类型。

比如:

  • 'true' == ['true']中,['true'] => 'true',所以'true' == 'true'结果为true
  • true == ['true']中,['true'] => 'true',然后'true' => NaN,而true => 1,所以1 == NaN结果为false
  • 同理[] == false[]先转换为字符串''''和false再都转换为0,结果为true
  • ![] == false 是因为需要先计算![]取反将其转换成布尔值,因为除了(''),NaN,0,null,undefined 转换成布尔值都为false[]转换成布尔值为true,取反为false,所以false==false,结果为true

注意:除了以上比较通用的对比方法,还有两个特殊的,null和undefined。Javascript规范中提到,要比较相等性之前,不能将 null 和 undefined 转换成其他任何值,并且规定null 和 undefined 是相等的。所以null 和undefined与其他的相比都是false,只有与其本身和null == undefined 才为true

+,-,*,/,% 运算

运算符+,-,*,/,%会出现隐式转换 不过很容易理解,运算符,只有数字才能运算。所以基本都是隐式转换为number类型 特殊的+运算符,因+有字符串拼接的左右,所有,当运算+的时候,如果两边存在字符串,是隐式转换为string类型

'+'运算符

常见的字符串拼接,加法运算

如果不会,建议重学

注意:任何Number与NaN相加都为NaN。 虽然null == undefined为true。但是Number(null)为0,Number(undefined)为NaN 所以,null + Number 等于 Number,但undefined+ Number 等于 NaN

转数值 只对null、""、布尔值、数值字符串、长度为1的数组并且数组内的值为数值或数值字符串、拥有valueOf方法并且返回的值为数值或数值字符串的对象,有效,其他均只能转为NaN

const num1 = +null;
const num2 = +"";
const num3 = +false;
const num4 = +true;
const num4 = +"123";
const num5 = +['321'];
const num6 = +{valueOf: function(){
        return '456';
    }}
// num1 num2 num3 num4 num5 num6 => 0 0 1 123 321 456

特殊现象

String({})为"[object Object]"
{} + [] => 0
[] + {} => "[object Object]"
[] + [] => ""
{} + {} => "[object Object][object Object]"
123 + {} => "123[object Object]"
'123' + {} => "123[object Object]"
{} + '123' => 123

目前还不是很清楚这种情况出现的理论知识,我是这样理解的当式子中只有一个{}时,并且当{}位于式子开头,认为{}是空的代码块,所以{} + []和{} + '123'变成+[]和+'123' 其他几项很明显进行了隐式转换,对象先转换成字符串,然后就直接做了字符串拼接。

对象的转换String(对象)和Number(对象)

var obj = {
    valueOf: function(){
        return 1;
    },
    toString: function(){
        return 2;
    }
};
var obj1 = {
    valueOf: function(){
        return 'a';
    },
    toString: function(){
        return 'b';
    }
};
var obj2 = {
    toString: function(){
        return 3;
    }
};
var obj3 = {
    valueOf: function(){
        return 'aa';
    },
};
console.log(Number(obj),String(obj),Number(obj1),String(obj1),Number(obj2),String(obj3)) 
// 1 "2" NaN "b" 2 "[object Object]"
//很明显能够看出Number方法会先调用valueOf(),如果没有再会去调用toString(),然后再次valueOf()
//而String方法只会调用toString(),没有找到,抛出类型