在讲JavaScript的数据类型隐式转换前,我们先看道面试题:
console.log(new String('abc') == true)
console.log({} == true)
console.log([] == ![])
结果是什么呢?
先把结果写下来,放在一边,然后继续看
创建字符串的三种方式:
var a = 'Davie' //申明的是一个string类型,它是一个基本类型
var a = String('Davie') // String()是一个包装类,用于将参数转换成string类型
var a = new String('Davie') //采用new方式时创建了一个object类型
使用typeof验证上面的结论
var a='Davie'
console.log(typeof a) //string
console.log(typeof String(a)) //string
console.log(typeof(new String(a))) //object
JavaScript的数据类型之前已经讲过了,忘记的小伙伴出门左转,查看**搞懂JavaScript的数据类型**
数据类型 | 转换为true的值 | 转换为false的值 |
---|---|---|
Boolean | true | false |
String | 任何非空字符串 | “” 空字符串 |
Number | 任何非零数字 | 0和NaN |
Object | 任何对象 | null |
Undefined | 不适用 | undefined |
!
转换规则!
会将后面的数据先转成布尔值,然后取反。例如:
var a;
var r = !!a;
console.log(r) //false
!!{} // true
!!undefined // false
!!nul // false
!!NaN //fales
==
比较比较操作符会为两个不同类型的操作数转换类型,然后进行严格比较。当两个操作数都是对象时,JavaScript会比较其内部引用,当且仅当他们的引用指向内存中的相同对象(区域)时才相等,即他们在栈内存中的引用地址相同。 —- 引用自MDN
var a = {}
var b = {}
a==b //false
很明显,a
和b
在堆内存中是两个对象。二另一种情况:
var a = {}
var b = a;
a==b //true
这时,a
和b
就指向了同一个对象,所以相等。
如果两边类型不同,则两边都尝试转成number类型。对于引用类型,先调用valueOf()
,如果能转成数字,则进行比较。不能转成数字就调用toString()
方法转成字符串。
var a = '123'
console.log(a == false) //false,'123'转成数字是123,右侧转成数字是0,最终比较123==0
console.log(a==123) //true,右边是数字,把左 边转成数字123
如果有一边是object类型:
var a = new String(123)
console.log(a==123) //true,a.valueOf()结果就是数字123,最终比较的是123==123
再看一个:
var a = {} console.log(a == 1)//上面a==1在js解释引擎中的执行过程如下://a.valueOf()获取到的不是基本类型,调用a.toString()得到'[object Object]''[object Object]'==1;//两边类型不致,左侧转成数字NaN==1;//false,NaN跟任何类型比较都为false
null、NaN、undefined和string、number、boolean、object类型比较时,都不做隐式转换,比较的结果直接为false。但是需要注意以下几个规则:
console.log(NaN==NaN) //falseconsole.log(undefined==null) //trueconsole.log(null==null) //trueconsole.log(null==undefined) //trueundefined == undefined //true
搞清楚规则后,开头的面试题就很容易了:
第一题:
//问题1:console.log(new String('abc') == true) //step1:右侧转成数字1,变成: new String('abc')==1 //step2 new String('abc').valueOf()不是数字也不是字符串,再调用toString() '[object Object]' == 1 //step3:字符串转数字 NaN == 1 //false,NaN和任何类型比较都为false
第二题:
//问题2:console.log({}==true)//step1:右侧转成数字{} == 1//step2 {}.valueOf()不是数字也不是字符串,再调用toString()'[object Object]' ==1 //step3:字符串转数字NaN == 1 //false,NaN和任何类型比较都为false
第三题:
//问题3:console.log([]==![])//step1:!优先级比==高,先转右边,[]是对象类型,转成布尔值为true,!true就是false[]==false//step2:右侧转成数字为0[]==0//step3:左侧是一个对象,valueOf()转出来不是字符也不是字符串,调用toString(),得到空字符串'' == 0//step4:字符串转成数字0 == 0 //true
valueOf()
转成number
toString()
方法转成string
>
<
来,在来看一道题:
console.log('666' < '7')
正确答案是 true
这是因为字符串类型比较大小时,不进行类型转换,而是逐位比较ascii码,第1位不同则返回结果,否则继续比较第2位,直到某一位不同为止。
在比如使用数组的sort方法排序:
var a=[1,10,6,100].sort()
结果是:
[1, 10, 100, 6]
原因是sort()方法默认的比较规则会先把每个元素转成字符串,然后比较字符串的ascii码来确定先后顺序。
+
+
运算符即可以对两个数相加,也可以连接字符串,那如果是[1,2,3]+4这种情况下又会发生什么呢?这就需要我们了解相应的规则,为了方便描述,我们把+号左侧的值叫做A,右侧的叫做B:
第一步:如果A和B都是number类型,直接相加;
第二步:接下来看A或B中是否有一个是否为string类型,如果有,则将另一个也转成字符串,然后连接;
第三步:既不是number,也不是string,则按如下规则转换:
调用valueOf()返回的结果:
调用toString()返回的结果:
-
除了加号外,减号也很神奇。
使用减号在做非数字类型的运算时,也会发生隐式类型转换.来看下面几个例子:
5 - true // 4
5 - '' //55 - null //5
5 - undefined // NaN5 - 'a' // NaN
5 - '1' //4