一、前言
js的数据类型总共六种(不考虑ES6的Symbol数据类型),分别是:Number、String、Boolean、undefined、null、Object;
所谓js的隐式转换,即相对于你主动去使用Number(),parseInt(),toString()等函数,将数据类型进行转换,而是在你没有采用这些函数进行数据类型转换的情况下,数据类型已经被悄悄的转换了。
js隐式转换本身是遵循一定的规则的,但是即使熟记一些规则之后,依然存在对一些js的隐式转换不是很理解。因此本文就将常用的类型转换规则一一例举出来,毕竟js数据类型既然就上面六种,再怎么转换也逃不过这六种之内。本文就关于实际的转换规则也会进行描述,但是,有时候强记可能来的更加高效。建议看完本文,会有收益的部分。
首先本文首先将隐式转换分为两类,一类为条件判断型的转换(以if形式的转换),另一类则为比较型的转换(以==号的转换)。
二、条件判断隐式转换
所谓条件判断,即就是if语句判断了,if语句中的判断要么是true要么是false,因此,条件判断的隐式转换,会将各种数据类型全部都转换为Boolean类型。举个例子如下:
// number
if(0){ // false
console.log(1);
}
// string
if("0"){ //true
console.log(0);
}
// object
if({}){ // true
console.log(1)
}
if类型的隐式转换较为简单,六种类型转为Boolean类型如下表格,其中null算在了Object中:
数据类型 | 转换为true的值 | 转换为false的值 |
---|---|---|
Boolean | true | false |
String | 任何非空字符串 | "" (空字符串) |
Number | 任何非零数字值(包括无穷大) | 0和NaN |
Object | 任何对象 | null |
Undefined | 不适用 | undefined |
三、比较型隐式转换
比较型的隐式转换,是基于使用==,>=,<=这类的比较符号,得出结果的true还是false。相对于条件判断要复杂很多,本文就仅讨论“==”双等号两边数据类型的隐式转换,会将六种数据类型中的两两逐一比较,综合得出各种结果。
(备注:对象Object的比较会单独拎出放在最后)
1. 数值与各种类型的比较
与数值比较,一般其他数据类型都会将转为数值,即to number,比如我们知道的true转为number是1,false是0。如果想知道其他类型转换为数值是多少的话,一般使用Number(xx),就可以了,因此我们将数值与其他类型的比较举例如下:
console.log(1 == 1) //true number
console.log(1 == "1") //true string
console.log(1 == true) //true boolean
console.log(1 == null) //false null
console.log(1 == undefined) //false undefined
console.log(0 == ""); // true
console.log(0 == []) //true
console.log(NaN == NaN) //false 然后顺便提下NaN,NaN是不和任何数值相等,也不等于自身,因此这种特性,可以用来判断该变量是否为NaN。
//还有更好玩的
console.log(null > 0) //false
console.log(null < 0) //false
console.log(null == 0) //false
console.log(null >= 0) //true
console.log(null <= 0) //true
console.log(null * 1 == 0) //true
数值比较一般规则:当两边都为数值时则直接比较,如果有一方不是数值的会转为数值,再进行比较,基本是执行Number(“不是数值一方的值”)进行转换。但是注意,null唯独特殊,看到有文章说null在==比较的时候不会进行类型转换(即使Number(null)被转换为0),因此null归null,是不相等于0的,所以就出现了后面的奇葩情况。(再注意Number(undefined)是为NaN)
2. 字符串与各种类型的比较
字符串与其他类型比较,如果比较的双方都是字符串的话,就直接比较,如果是不同类型的话,要进行隐式转换的了。所以先看看结果:
console.log("1" == "1") //true 1
console.log("1" == 1) //true 2
console.log("1" == true) //true 3
console.log("1" == null) //false 4
console.log("1" == undefined) //false 5
console.log("" == false) //true 6
console.log("" == null) //false 7
console.log("" == undefined) //false 8
console.log("" == 0) //true 9
console.log("0" == 0) // true 10
console.log("" == "0") //false 11
console.log("0" == false) //true 12
console.log("false" == false) //false 13
console.log("undefined" == undefined) //false 14
字符串比较一般规则:如果两边都是字符串则直接比较,如果有一边不是,一般经验是先将字符串转为数字,然后再使用数字比较的规则来判断。
比如14号,Number("undefined")返回NaN,Number(undefined)也返回NaN,我们有知道NaN不相等,所以14号是false.是不是很好用呢?(一开始设计NaN和其他什么都不相等总会有点奇怪,通过这个比较,是不是又会觉得NaN和什么都不等,又很有道理呢?)
然后想必读者也注意到9号,10号,11号和6号,11号,12号,会发现有个奇怪的现象,比如"" == false,"0" == false,为true,然而"" == "0"为false?很蹦三观,a=b,b=c,a居然不等于c?但在js这里的隐式转换却也有理,可能这就是编程的魅力吧。
3. 布尔型与其他类型的比较
布尔型与数字,字符串比较过了这里不多写了,就写下没比较过的,请看看结果:
console.log("" == false) //true
console.log("1" == true) //true
console.log(false == null); //false
console.log(false == undefined) //false
console.log(true == null); //false
console.log(true == undefined) //false
布尔型比较规则,比较方式基本与字符串相同,如果都是boolean可以直接比较,若不是,则可以先转为数字再比较。
这里很有意思的现象,false和true都不相等于null或者undefined,结果都是false,这也验证了一个事实,毕竟世上不是非黑即白,也没有绝对的对错之分。当然我们知道规则是因为true和fasle被转为1和0了,然后再比较就知道为什么不相等。
4.null和undefined的比较
看了之前比较,想必你注意到了两个奇葩,null和undefined基本不和其他数据类型玩得来,返回都是false,那么他们两个呢?
console.log(null == undefined) // true
原来他两个是好基友,他两个在两等于号情况下竟然是相等的,切记此处需要记住!
console.log(null === undefined) // false 严格的三等于号,由于数据类型不同所以不相等
5. 对象比较
复杂数据类型对象Object的隐式转换,不同于其他简单数据类型,它基于一定的规则:
对象与其他不同数据类型比较
在对象与其他不同的类型比较的时候,首先会将对象本身换为primitive值,然后进行之间的相互比较。转换为primitive值的有两个常用函数,一个名为valueOf(),另一个名为toString()。
一般转换方式:首先执行valueOf()函数(其优先级高),如果有该函数并得到返回值,则转换为该值;如果没有,再执行toString()函数,如果有该函数并得到返回值,则转换为该值。
为了验证规则,我们举个简单的例子:
// 1
var one = {
valueOf(){
return 1;
},
toString(){
return 2;
}
}
// valueOf的优先级高
console.log(one == 1) //true
console.log(one == 2) //false
// 2
var two= {
toString(){
return 2;
}
}
//没有valueOf则执行了toString
console.log(two == 2) //true
// 3
var three = {};
//啥也没有
console.log(three == 1) //false
一个对象居然是可以等于一个数字!理清思路,上面例子是对象和数值进行比较,得出的是true,首先有的valueOf函数则执行valueOf函数返回1,没有的话返回toString的函数结果2,与数值相等,因此为true。
对象之间的比较
对象间的比较也是直接比较,因为对象之间比较的是地址,不涉及数据的隐式转换,所以任意两个对象总是不相等的,举例:
//试试
var a = {valueOf(){return 1}}
var b = {valueOf(){return 1}}
console.log(a == b) //false 没有转为数值,而是不等。
看上面都为结果,依照对象之前的规则似乎相等,但是因为都是对象,我们学过其他语言都明白,对象的比较都是地址,所以两个对象总是不同的。虽然a == b不可以,但是a == 1依旧是可以的。
插曲1:其他数据类型对象的转换
关于对象的转换规则,也是适用于其他数据类型对象的,Number对象、String对象等等也都被附上了valueOf函数和toString函数,在转换中可以获取到其primitive值,比如:
var a = new Number("1");
console.log(a.valueOf()) // 1
var b = new String("1");
console.log(b.valueOf()) // "1"
//注意上面一个是返回数字,一个返回字符串
console.log(typeof a.valueOf(), typeof b.valueOf()); // number string
// 然后
console.log(a == b) // false
是不是又感觉奇怪了,之前1 == "1"是相等的返回true,到这里居然又返回false,原来是因为这里使用了对象的创建方式,符合对象的比较规则,即使一个返回字符1,一个数字1,但是比较的是对象,两者的地址是不会相等的。(这也是我之前部分隐式转换不明白的原因,需要区别对象1和数字1,这两者的不同)
插曲2:玩玩js隐式转换
学有所成,当然要实践了,因此基于上面的规则,我们可以这样做:
var obj = {
_num:1,
valueOf(){
return this._num++;
},
}
console.log(obj == 1) //true
console.log(obj == 2) //true
惊呆!居然有东西既可以等于1又可以等于2,明显违反了数学理论,但是很抱歉...js编程就是可以,可能js魅力也就是这样。
插曲3:对于空数组[]
数组也属于对象,它在隐式转换的时候却和一般对象稍有不同:
console.log([] == 1) //false
console.log([] == 0) //true
console.log([] == {}) //false
console.log([] == "") //true
console.log([] == null) //false
console.log([] == undefined) //false
我们知道关于数组强制转换为数字为0(Number([]) == 0),然而空对象{}强制转换为NaN,所以空数组就有了不一样的情况。
继续深入,这是为什么会强制转换结果不一样呢?根据上面的描述,想必读者明白,数组是对象,数组当然也被赋有了valueOf和toString函数,空数组的valueOf返回的是数组本身,不是数值,所以转而执行toString()函数,空数组返回了空字符串,因此上面的比较结果是与空字符比较结果相同。
6.请看题
基本隐式转换,已经告下帷幕了,但是你真的就会觉得,已经都学会了吗?
请看题,这里有个隐式转换:
// (!(~+[])+{})[--[\~+""][+[]]*[~+[]]+~~!+[]]+({}+[])[[~!+[]*~+[]]]
输出结果是什么呢,不会的话F12测试下吧,看看返回什么,呵呵。0.0
来源于:
npm i -g zhuangbility
//然后运行
zhuangbility 你想转换的文字'
四、尾语
js的隐式转换还是很多要记得,本文将隐式转换分为两类来讲,着重描述了隐式转换的比较类型的结果。
欢迎转载,但是转载前,请先联系作者,如有偷转抄袭一经发现必究。
本文如有不正欢迎指正。
最后祝大家生活愉快!
网友评论