众所周知JS是弱类型语言,弱类型语言的最大特点是允许隐式类型转换,即源码中没有明显的类型转换代码,也就是说你可以为一个变量赋值为字符串、也可以赋值为数值,也可以让不同类型的变量进行相加。语言的解析器会自动(隐式)转换。
隐式转换规则
1、转成string类型: + (字符串连接符)
2、转成Number类型:++/-- (自增自减运算符) ±*/%(算术运算符)> 、< 、>=、<=、、!=、=、!== (关系运算符)
3、转成boolean类型:!(逻辑运算符)
但是在实际应用中,我们总是会分不清 + 是作为字符串连接还是算术运算符。让我们看一下下面的列子,你觉得它会返回什么?
console.log( 1 + 'true')
console.log( 1 + true )
console.log( 1 + undefined )
console.log( 1 + null )
正确答案是:
1true
2
NaN
1
让我们分析一下,首先要理解+什么时候作为字符串连接符什么时候为算术运算符,以及其作用。
字符串连接符(+ : 只要+号的两边有一边是字符串)
算术运算符 ( 两边都为数字 )
1、字符型连接符+ :会把其他数据类型调用string()方法转成字符串然后进行拼接。
2、算术运算符 + :会把其他数据类型调用number()方法转成数字然后再做加法运算
1+ "true" ----> String(1) + "true" ---> 1true
1+true -----> 1+ Number(true) ----> 1+ 1 -----> 2
1+undefined ----> 1+ Number(undefined)----> 1 + NaN ---> NaN
1+null -----> 1+ Number(null) -----> 1+ 0----> 1
关系运算符:把其他数据类型转成Number之后再进行比较
console.log( '2' > 10 )
结果为false '2' > 10----> Number(2) > 10 ----> true
console.log( '2' > '10' )
结果为true,当关系运算符两边都是字符串的时候,同时转为number然后比较,但是此时比较的并不是按照number()转成的数字,而是按照字符串对应的unicode编码来转成数字。可以通过 str.charCodeAt() 来获取unicode
'2'.charCodeAt()---->50
'10'.charCodeAt()---->49
console.log( 'abc' > 'b' )
同理比较的也是unicode编码
'a'.charCodeAt()---->97
'b'.charCodeAt()---->98
特殊情况:
console.log( NaN == NaN ) ----> false
console.log(undefined == null) -----> true
复杂数据类型在隐式转换时会先转成string,然后再转成number运算
一个常见的面试题:
var a = ???
if(a == 1 && a == 2 && a ==3 ){
console.log(1)
}
我们可以利用复杂数据类型,调用valueOf()然后转成number,对象的valuueOf()方法也是可以重写的。
var a = {
i :0,
valusOf: function(){
return ++a.i // 没调用一次就让a的i属性自增一次并返回
}
}
逻辑非隐式转换与关系运算符隐式转换
console.log ([] == 0 )
结果为true, [] ----> [].valueOf().toString() ---> '' == 0 ----> Number('') == 0;
那 ![] == 0的结果应该为true,还是false呢
答案是true。
要想理解,我们要先弄明白非(!)运算符
*逻辑非:将其他数据使用Boolean()转成布尔类型
只有以下八种情况转换为Boolean会得到false,除此之外都为true
0、-0、NaN、undefined、null、空字符串、false、document all()
我们再来看两个列子:
console.log( [] == [] );
// false 原因:引用类型数据存在堆中,栈中存储的是地址,所以为false
console.log( ![] == [] )
[].valueOf().toString() ---> ''
![] -----> false
Number('') ==Number(false) ---> true