隐式转换
测试类型: 1 -1 0 NaN '' 'a' '1' true false null undefined [] [1,2,3] {} {a:1}
本文章将根据以上几种类型进行测试和解析 其他类型请自行测试或者联系博主哟~
隐式转换介绍
在js中,当运算符在运算时,如果两边数据(这里为啥不写数据类型呢是因为两边的类型不同其实也会发生隐式转换,往下看你会更加了解)不统一,CPU就无法计算,编译器会自动将运算符两边的数据做一个数据类型转换,转成一样的数据类型再计算,这种无需程序员手动转换,而由编译器自动转换的方式就称为隐式转换
小小的例子:
例如1 > "0"这行代码在js中并不会报错,编译器在运算符时会先把右边的"0"转成数字0`然后在比较大小
console.log(1 >'0')//true
隐式转换规则
第一大类:转为string类型
看到这种形式 ? + str (字符串连接符 + )就会发生转换为string 拼接其他类型的数据
console.log(1 + 'str');//1str
console.log(-1 + 'str');//-1str
console.log(0 + 'str');//0str
conlose.log(NaN+'str');//NaNstr
console.log(true + 'str');//truestr
console.log(false + 'str');//falsestr
console.log(null + 'str');//nullstr
console.log(undefined + 'str');//undefinedstr
//-----------------------------------------------------------------------------------
//下面的这些后面会陆续讲到 现在看不太懂没有关系 属于坑三
console.log([] + 'str');//str
console.log([1, 2, 3] + 'str');//1,2,3str
console.log({} + 'str');//[object Object]str
console.log({ a: 1 } + 'str');//[object Object]str
第二大类:转为number类型
第一种情况:
看到 ? + - * / % number 就会发生转换number 进行算术运算
console.log('' + 1)//'1'
console.log('a' + 1);//'a1'
console.log('1' + 1);//'11'
console.log(NaN + 1);//NaN
console.log(true + 1);//2
console.log(false + 1);//1
console.log(null + 1);//1
console.log(undefined + 1);//NaN
//-----------------------------------------------------------------------------------
//这个和上面那个一样后面会陆续讲到,现在看不懂没有关系 属于坑三
console.log([] + 1)//1
console.log([1, 2, 3] + 1);//'1,2,31'
console.log({} + 1);//'[object Object]1'
console.log({ a: 1 } + 1);//'[object Object]1'
这里可以看到前三行的结果是字符串型 不对呀 转换为number不是应该出来的结果不应该都是number类型吗?(强调:NaN是number类型),看到这里隐式转换的第一个坑就出现了!!!
坑一:字符串连接符与算术运算符隐式转换规则混淆
别害怕 虽然有坑 但是咱们有坑一宝典 :string>number>boolean
其实这里是有一个转换顺序的 就是我们看到 + 时候两边数据不一样时 先看有没有string如果有不要犹豫 就是拼接 如果没有看有没有number如果有就把另外一个数据转换为number在进行运算,所以这边前三行看到string了直接拼接了就没有再运算,这样我们就不怕第一个坑了!!
有的小伙伴会问了,+会了 那别的- * / %运算呢?也是有规则的.
‘’ null false 当做数值0 true '1' 当做数值1
([] {} 遵循复杂数据类型的隐式转换 下面会讲到)
纯数字字符串 转换为number运算
NaN 'ABC' undefined [1,2,3] {name:abc} 结果是Na
console.log('' - 1)//-1
console.log('a' - 1);//NaN
console.log('1' - 1);//0
console.log(NaN - 1);//NaN
console.log(true - 1);//0
console.log(false - 1);//-1
console.log(null - 1);//-1
console.log(undefined - 1);//NaN
//--------------------------------------------------------------------------
console.log([] - 1)//-1
console.log([1, 2, 3] - 1);//NaN
console.log({} - 1);//NaN
console.log({ a: 1 } - 1);//NaN
第二种情况:
> < >= <= == === != !== (关系运算符)
坑二:关系运算符会把其他数据类型转换成number之后再比较关系
坑二宝典:
'' [] false 当做数值0
{} NaN undefined null当做非数字 NaN
注意:null在遇到除== === != !==以外的关系运算符时将转换为0
console.log(null>-1);//true
console.log(null>=-1);//true
console.log(null<1);//true
console.log(null<=1);//true
console.log(null==0);//false
console.log(null===0);//false
console.log(null!=0);//true
console.log(null!==0);//true
单个字符串比较unicode编码 (始终遵循A<Z<a<b)
多个字符串比较从左往右依次单个比较(这里注意不会比完有一个不一样就比出结果了)
比如:'abc'>'aaaaaaaa' (虽然右边的长但是在比较第二个字符时左边的‘b’就已经>右边的'a'了)
3个特殊情况
NaN==NaN //false
null==undefined //true
null===undefined //false
console.log('' == 0);//true
console.log([] == 0);//true
console.log(fasle == 0);//true
console.log({} == 0);//false
console.log(NaN == 0);//false
console.log(undefined == 0);//false
console.log(null == 0);//false
//特殊情况:无视规则
console.log(NaN == NaN);//false
console.log(null == undefined);//true
console.log(null === undefined);//false null--object undefined----undefined
//----------------------------------------------------------------------------------
console.log('2' > 10);//false
console.log('2'.charCodeAt());//50
console.log('2' > '10');//true
console.log('10'.charCodeAt());//49
console.log('a' > 'b');//false
console.log('a'.charCodeAt());//97
console.log('b'.charCodeAt());//98
console.log('z'.charCodeAt());//122
// a - z 97 - 122
console.log('a'>'A')//
console.log('A'.charCodeAt());//65
console.log('Z'.charCodeAt());//90
//A-Z 65-90
//A<Z<a<z
// 长条字符串从左到右依次比较
console.log('abc' > 'b');//false
console.log('abc' > 'aad');//true
第三大类:转成boolean类型
看到 !(逻辑非运算符)就会发生此类隐式转换
规则:0 -0 NaN '' null undefined ------false 这六大类在转换时会转换成false
console.log(!1);
console.log(!-1);
console.log(!0);//true
console.log(!NaN)//true
console.log(!'')//true
console.log(!'a');
console.log(!'1');
console.log(!true);
console.log(!false);//true
console.log(!null);//true
console.log(!undefined)//true
console.log(![])
console.log(![1, 2, 3])
console.log(!{})
console.log(!{ a: 1 })
坑三:复杂数据类型在隐式转换时会先转成String,然后再转成Number运算
//经典面试题
var a = ? ? ? ;
if (a == 1 && a == 2 && a == 3) {
console.log(1)
}
//给a设置内容 让他实现值同时等于1 2 3
要想做这个题 必须了解复杂类型隐式转换的顺序:
复杂类型转number顺序如下:
1.先使用valueOf()方法获取原始值,如果原始值不是number类型,则使用toString()转换为字符串型
2.再将这个string转为number运算
这时候上面那个经典面试题就可以做出来了
var a = {
i:0,//声明一个属性i
valueOf:function(){
return ++a.i;//每调用一次,让对象的a属性的i值自增并返回
}
} ;
if (a == 1 && a == 2 && a == 3) {//没运行每次运算时都会调用一次a的valueOf方法
console.log(1)
}
分析过程:
1.a是对象是引用类型 先调用valueOf()获取a的原始值 返回a.i 也就是1 这时候a==1成立了
2.接着比较a==2 再调用valueOf 这时候得到 2 成立 之后再判断a==3
3.都成立了 打印1
坑三了解到这里 上面我们没解决的问题也迎刃而解了 !!
console.log('' + 1)//'1'
console.log('a' + 1);//'a1'
console.log('1' + 1);//'11'
console.log(NaN + 1);//NaN
console.log(true + 1);//2
console.log(false + 1);//1
console.log(null + 1);//1
console.log(undefined + 1);//NaN
//-----------------------------------------------------------------------------------
//这些后面会陆续讲到,现在看不懂没有关系 属于坑三
console.log([] + 1)//1
console.log([1, 2, 3] + 1);//'1,2,31'
console.log({} + 1);//'[object Object]1'
console.log({ a: 1 } + 1);//'[object Object]1'
console.log('' - 1)//-1
console.log('a' - 1);//NaN
console.log('1' - 1);//0
console.log(NaN - 1);//NaN
console.log(true - 1);//0
console.log(false - 1);//-1
console.log(null - 1);//-1
console.log(undefined - 1);//NaN
//--------------------------------------------------------------------------
console.log([] - 1)//-1
console.log([1, 2, 3] - 1);//NaN
console.log({} - 1);//NaN
console.log({ a: 1 } - 1);//NaN
这里我们可以看到
[]空数组
console.log([]+1)//'1'
分析过程:
1.引用类型 调用valueOf() 获取原始值 不是number类型
2.调用toString() 变成 '' 不是number类型
3.但是这时候简化为console,log(''+1) 这个结果大家肯定轻车熟路了 '1'
console.log([]-1)//-1
分析过程:
1.引用类型 调用valueOf() 获取原始值 不是number类型
2.调用toString() 变成 '' 不是number类型
3.但是这时候简化为console,log(''-1) 上面讲过''会当做数值0
4.所以这个结果就是数值型 -1
[1,2,3]非空数组
console.log([1,2,3]+1)//'1,2,31'
分析过程:
1.引用类型 调用valueOf() 获取原始值 不是number类型
2.调用toString() 变成 '1,2,3' 简化为console.log('1,2,3'+1)
3.看到+ 看到str 字符串拼接 结果就是 '1,2,31'
console.log([1,2,3]-1);//NaN
分析过程:
1.调用valueOf()方法获取原始值 不是number类型
2.调用toStrng()方法转换为字符串 '1,2,3' 这时候简化为cosnole.log('1,2,3'-1)
3.非空数组转换为number 为NaN这时候简化为console.log(NaN-1) 结果就是NaN
对象不论是空对象还是非空
console.log({} + 1);//'[object Object]1'
console.log({ a: 1 } + 1);//'[object Object]1'
分析过程:
1.引用类型 调用valueOf() 获取原始值 不是number类型
2.调用toString() 变成 '[object Object]' 这时候简化为console.log('[object Object]'+1)
3.看到 + 看到str 字符串拼接 所以结果就是 '[object Object]1'
console.log({}-1)//NaN
console.log({a:1}-1)//NaN
分析过程:
1.引用类型 调用valueOf() 获取原始值 不是number类型
2.调用toString() 变成 '[object Object]' 这时候简化为console.log('[object Object]'-1)
3.不是纯数字的字符串转换为number类型 为NaN 所以结果就是NaN
坑四:逻辑非隐式转换与关系运算符隐式转换搞混淆
前方高能,请注意~ (其实跟运算符优先级有关系也不是无规则可循)
大坑:
console.log([]==0);//true
左边[] 遇到关系运算符 转换为0
最终等式转换为 0==0
console.log(![]==0);//true
左边![] 转换为布尔值 false
等式转换为 false==0
左边false 遇到关系运算符 转换为0
最终等式转换为 0==0
神坑:
console.log([]==![]);//true
右边![] 转换为布尔值 false
左边[] 遇到关系运算符 转换为0
等式转换为 0==false
右边false 遇到关系运算符转换为0
最终等式转换为 0==0
console.log([]==[]);//false
引用类型数据存在栈中 栈中存储的是地址 所以结果是false
史诗级坑:
console.log({}==!{});//false
右边!{} 转换为布尔值 false
左边{} 遇到关系运算符 转换为NaN
等式转换为 NaN==false
右边false 遇到关系运算符 转换为0
最终等式转换为 NaN==0
console.log({}=={});//false
引用类型数据存在栈中 栈中存储的是地址 所以结果是false
坑五:之前从未见过的坑
取正数
" false null [] 当做0 ;
true [1]当做1;
'a' NaN undefined [1,2] {} {a:1} 当做NaN
console.log(+1);//1
console.log(+-1);//-1
console.log(+0);//0
console.log(+NaN)//NaN
console.log(+'')//0
console.log(+'a');//NaN
console.log(+'1');//1
console.log(+true);//1
console.log(+false);//0
console.log(+null);//0
console.log(+undefined)//NaN
console.log(+[])//0
console.log(+[1])//1
console.log(+[1, 2, 3])//NaN
console.log(+{})//NaN
console.log(+{ a: 1 })//NaN
取负数
" false null [] 当做0 ;
true [1]当做1;
'a' NaN undefined [1,2] {} {a:1} 当做NaN
console.log(-1);//-1
// console.log(--1);//报错---------
console.log(- -1);//1------------
//console.log(- (-1))-------------
console.log(-0);//-0
console.log(-NaN)//NaN
console.log(-'')//-0
console.log(-'a');//NaN
console.log(-'1');//-1
console.log(-true);//-1
console.log(-false);//-0
console.log(-null);//-0
console.log(-undefined)//NaN
console.log(-[])//-0
console.log(-[1])//-1
console.log(-[-1])//1
console.log(-[1, 2, 3])//NaN
console.log(-{})//NaN
console.log(-{ a: 1 })//NaN
经典面试题
console.log('a'+ + 'b')//aNaN
分析过程:
1.根据优先级 先让后面的+和'b'结合 进一步简化console.log('a' + (+'b'))
2.(+'b')的结果是NaN 进一步简化console.log('a' + NaN)
3.看到+ 和 str 拼接 结果就是 'aNaN'
看到这里 一定很混乱吧 但是隐式转换就是这么多这么麻烦 那能怎么办呢 只能多看多练 最后的最后 博主布置一个经典面试题 做出来的小伙伴可以在评论区交流哦~
经典面试题:
console.log([1,2,3]+{user:name})