我们需要了解任何计算都只能在相同的数据类型之间执行。如果我们强制JavaScript执行执行一些操作,例如在字符串中添加一个数字,在这种情况下,js编译器会默认将数字更改为字符串类型,然后将两者连接起来,这就是类型转换。
什么是类型转换?
在JavaScript中,类型转换是将一种数据类型转换为另一种数据类型,例如字符串转为数字,对象转为布尔值等。
使用不同的数据类型执行操作时,需要进行类型转换。这些转换可以由JavaScript编译器自动执行,也可以由我们手动执行。
我们看几个示例:
console.log('1' + 2) //'12'
console.log(1 + 'js')//1js
console.log(1 + 2)//3
console.log(1 + 2 + '1')//31
console.log(1 + '2' + 1)//121
console.log('6' - 2) // 4
console.log('6' * 2) // 12
console.log('6' / '2')//3
console.log(null == 1)//false
console.log('abc' - 1)//NaN
示例中使用不同的数据类型,默认情况下,js编译器对字符串类型数据使用 -、*、/ 运算符时会将字符串转换为数字;
而+运算符与其他运算符有所不同,+运算符执行两个功能:
1.数学加法
2.字符串串联
当对字符串使用+运算符操作时,js不是将字符串转为数字,而是将数字转换为字符串。
对于松散相等 == 运算符,如示例中,会把null转换为Number类型:0,热后比较0==1,返回false.
对于非数字型字符串使用-、*、/运算符,如示例中‘abc’-1,js编译器无法将‘abc’转换为数字类型,会返回NaN,表示不是一个数字。
类型转换的类型
在js中,有两种类型转换:隐式类型转换和显式类型转换。
- 隐式类型转换:js编译器自动执行类型转换。
- 显式类型转换:我们手动执行类型转换。
常见的数据转换:
- 字符串的转换
- 数字的转换
- 布尔值转换
字符串转换
我们通常使用String()方法将其他数据类型转换为字符串类型,我们来看下面的示例。
//隐式转换
'15' + 36 // '1536' 36转为'36'
'20' + null //'25null' null转为'null'
'abc ' + undefined //'abc undefined' undefined转为'undefined'
'2' - 1 // 1 '2'转为2
6 / '2' //3 '2'转为2
'4' * 2 // 8 '4'转为4
//显式转换
String(23) // '23'
String(true) // 'true'
String({}) // '[object Object]' 调用目标对象toString()方法
String([]) // ''
在字符串和数字间使用-、*、/运算符,js编译器会将字符串转换为数字,如果是非数字型字符串,返回NaN;对于+运算符,会将数字转为字符串。
数字转换
我们可以使用Number()方法将其他类型数据显式转为数字类型。
//隐式转换
'' == 0 //true
[] == 0 // true []=>'' '' == 0
true == 1 //true true=>1
false == 0// true false=>0
//显式转换
Number('12') // 12
Number('-12.34') // -12.34
Number('abc') // NaN
Number(null) // 0
Number(undefined) // NaN
Number({}) //NaN 调用目标对象valueOf()方法
非数字型字符串、undefined、对象在转换为数字类型时会转为NaN。
布尔值转换
我们可以使用Boolean()方法将其他数据类型转换为布尔类型。每一个js值都可以强制转换为true或false。在js中,以下值在转换为Boolean后返回false:
• false
• 0
• -0
• undefined
• ""
• NaN
• null
其他一切值都返回true。
Boolean(-1)//true
Boolean({})//true
Boolean([])//true
Boolean('0')//true
比较运算符、==、===
我们来看一下对于其他运算符的类型转换。
'2' > '1' // true 字符串之间比较第一个字符的Unicode编码 2.charCodeAt()>1.charCodeAt()
'2' > '10' // true 2的Unicode编码比1大 只比较第一个字符
'2' > 10 // false 字符串'2'转为数字2 然后进行比较
'abc' > 'aab' // true 先比较'a'和'a',两者相等,比较下一个字符,'b'>'a'
NaN == NaN // false NaN与任何数据比较都返回NaN
[] == 0 //true [].toString()='' Number('') == 0成立
![] == 0 // true []转为布尔为true 取反得false false == 0 成立
[] == [] //false 引用数据类型存在堆中 栈存的地址引用 两个数组地址不同 返回false
[] == ![] //true
{} == {} //false 类型相同 直接比较 堆内存地址不同 返回false
{} == !{} //false // ????
我们发现了一个问题,为什么{} == {}返回false,{} == !{}也返回false,这是这么回事?
对于严格等于===运算符,会有严格得类型判断,对于对象和数组只看双方地址;对于松散等于==在比较时,如果双方类型相等,进行值或者地址比较,如果类型不相等,先进行类型转换,在比较值或者地址,所以[] == []和{} == {}返回false,因为堆内存中地址不同;我们还需要了解一下==运算符类型转换规则:
- 如果有一个操作数是布尔值,会将其转换为数字类型再进行比较,true:1,false:0;
- 如果一个操作数是字符串,另一个操作数是数值,会先将字符串转换为数值在进行比较,当左右两边类型相等时,采用===运算符断定规则。
回归正题,{} == !{}右侧为Object类型,左侧为Boolean类型,所以要将两侧操作数转换为Number类型,Number({})返回NaN,{}隐式转换为true,!{}等于!true =>false,Number(false)等于0,所以最终运算为NaN == 0,NaN与任何值比较都返回false,故结果为false。
额外补充
有一个需要我们关注的点,看下面这个示例:
3 === new Number("3") // false
3 === Number("3") // true
两行代码都将String类型的‘3’转换成数字3,但返回结果不同;第一行代码返回false,因为我们创建了一个Number对象的实例,返回的是这个实例的引用;而第二行代码返回的是一个原始的数据类型,所以结果是true。
typeOf new Number("3") // object
typeOf Number("3") // number
typeOf 3 // number