什么是隐式类型转换?
我们在开发的过程中,很多时候都会用到双等号 == 进行判断,以决定接下来执行哪些业务逻辑。
隐式类型转换:==在比较两个不同类型的值时会发生隐式类型转换,会将其中之一或两者都转换为相同类型后再进行比较。
那么转换的规则是什么呢?
隐式类型转换的规则
字符串和数字做相等比较,会把字符串转为数字
let a = 10;
let b = '10';
console.log(a == b); //true
有布尔值时,会把布尔值转为数值
let a = true;
let b = '1';
console.log(a == b); //true
上述代码中,a和b做比较,a会先变为数值1(true对应1,false对应0),然后是数值1和字符串1做比较,那么会应用第一条规则
在==中,null和undefined是相等的
let a = null;
let b;
console.log(a == b);//true
我们观察上述第一和第二条规则,不难发现,在进行隐式类型转换时, 双等号==更加偏爱数值,也就是说,在进行比较时,js会调用Number函数把双等号两边的值转为数值,下面我们来聊聊Number这个内置函数。
Number函数
作用:Number() 函数把对象的值转换为数值,如果对象的值无法转换为数值,那么Number函数则返回NaN。(如果参数是 Date 对象,Number() 返回从 1970 年 1 月 1 日至今的毫秒数)
我们来观察如下代码的输出:
console.log(Number())
console.log(Number(0))
console.log(Number(''))
console.log(Number('0'))
console.log(Number(false))
console.log(Number(null))
console.log(Number([]))
console.log(Number([0]))
console.log(Number('str'))
上述代码中,除了最后一行外,其余的输出都为0,而最后一行的输出是NaN,因为Number()函数无法把字符串转为数值,但是可以把数字类型的字符串转为数值(第四行代码)
为了更好地理解我们接下来要给出的面试代码题,我们先来讨论一下Boolean函数。
Boolean()函数
我们在开发中,或许会写过如下类似的条件判断语句:
if (1) {
console.log('success');
}
上述代码会输出success,因为if的条件为真,原因在于if语句在判断时,调用了Boolean()函数,即Boolean(1) 的值为true。
Boolean函数的作用机制如下:
在js中,除了0,-0,NaN,’"",null,undefined这六个值转为布尔值时,结果为false,其它任何对象转为布尔值,都得到 true。
console.log(Boolean(0));//false
console.log(Boolean(-0));//false
console.log(Boolean(NaN));//false
console.log(Boolean(""));//false
console.log(Boolean(null));//false
console.log(Boolean(undefined));//false
console.log(Boolean([]));//true
console.log(Boolean({}));//true
console.log(Boolean('false'));//true
console.log(Boolean(Date.now()));//true
代码输出题
我们观察如下代码:
if ([] == false) {console.log(1)}
if ({} == false) {console.log(2)}
if ([]) {console.log(3)}
if ([1] == [1]) {console.log(4)}
我们来分析一下上述代码。第一第二行代码,双等号两侧会调用Number()函数,Number([])=Number(false)=0,所以会输出1,而Number({})的返回值是NaN,NaN == 0的返回值是false,所以2不会输出。第三行代码会调用Boolean()函数,Boolean([])的返回值是true,所以3会输出。
我们来观察一下第四行代码,乍看之下,好像4一定会输出,因为双等号两侧会调用Number()函数,而Number([1])=1,1==1返回true,那么就会输出4,这样分析好像没毛病。然而,上述代码不会输出4。
当双等号两边的值都是引用数据类型(数组和对象)时,规则不再适用,因为引用数据类型比较的是引用地址,如果两个值的引用地址是一样的,那么它们相等,否则不相等,上述[1] 和 [1]的引用地址不一样。我们可以用如下规则来判断引用数据类型:
如果==两边的值都是对象,则比较它们是不是同一个对象,如果两个值都指向同一个对象,则返回 true;否则, 返回false
console.log([] == []);//false
console.log({} == {});//false
let a = {};
let b = a;
//a和b指向同一个对象,所以返回true
console.log(a == b);//true
let c = [];
let d = c;
console.log(c == d);//true