举个例子:前端
console.log(1 + '1')
在 JavaScript 中,这是彻底能够运行的,不过你有没有好奇,为何 1 和 '1' 分属不一样的数据类型,为何就能够进行运算呢?git
这实际上是由于 JavaScript 自动的将数据类型进行了转换,咱们一般称为隐式类型转换。可是咱们都知道,+
运算符既能够用于数字加法,也能用于字符串拼接,那在这个例子中,是将数字 1
转成字符串 '1'
,进行拼接运算?仍是将字符串 '1'
转成数字 1
,进行加法运算呢?github
先卖个关子,虽然估计你也知道答案。今天,咱们就常见的隐式类型转化的场景进行介绍。面试
console.log(+'1');
当 + 运算符做为一元操做符的时候,查看 ES5规范1.4.6,会调用 ToNumber
处理该值,至关于 Number('1')
,最终结果返回数字 1
。数组
那么下面的这些结果呢?微信
console.log(+[]); console.log(+['1']); console.log(+['1', '2', '3']); console.log(+{});
既然是调用 ToNumber
方法,回想《JavaScript 深刻之头疼的类型转换(上)》中的内容,当输入的值是对象的时候,先调用 ToPrimitive(input, Number)
方法,执行的步骤是:闭包
obj
为基本类型,直接返回valueOf
方法,若是返回一个原始值,则 JavaScript
将其返回。toString
方法,若是返回一个原始值,则JavaScript
将其返回。JavaScript
抛出一个类型错误异常。以 +[]
为例,[]
调用 valueOf
方法,返回一个空数组,由于不是原始值,调用 toString
方法,返回 ""
。app
获得返回值后,而后再调用 ToNumber
方法,""
对应的返回值是 0
,因此最终返回 0
。函数
剩下的例子以此类推。结果是:工具
console.log(+['1']); // 1 console.log(+['1', '2', '3']); // NaN console.log(+{}); // NaN
如今 +
运算符又变成了二元操做符,毕竟它也是加减乘除中的加号
1 + '1'
咱们知道答案是 '11',那 null + 1
、[] + []
、[] + {}
、{} + {}
呢?
若是要了解这些运算的结果,不可避免的咱们要从规范下手。
规范地址:http://es5.github.io/#x11.6.1
不过此次就不直接大段大段的引用规范了,直接给你们讲简化后的内容。
到底当执行 +
运算的时候,会执行怎样的步骤呢?让咱们根据规范11.6.1
来捋一捋:
当计算 value1 + value2时:
规范的内容就这样结束了。没有什么新的内容,ToString
、ToNumber
、ToPrimitive
都是在《JavaScript 深刻之头疼的类型转换(上)》中讲到过的内容,因此咱们直接进分析阶段:
让咱们来举几个例子:
console.log(null + 1);
按照规范的步骤进行分析:
接下来:
ToNumber(null)
的结果为0,(回想上篇 Number(null)),ToNumber(1)
的结果为 1
因此,null + 1
至关于 0 + 1
,最终的结果为数字 1
。
这个还算简单,看些稍微复杂的:
console.log([] + []);
依然按照规范:
因此,[] + []
至关于 "" + ""
,最终的结果是空字符串""
。
看个更复杂的:
// 二者结果一致 console.log([] + {}); console.log({} + []);
按照规范:
因此,[] + {}
至关于 "" + "[object Object]"
,最终的结果是 "[object Object]"。
下面的例子,能够按照示例类推出结果:
console.log(1 + true); console.log({} + {}); console.log(new Date(2017, 04, 21) + 1) // 这个知道是数字仍是字符串类型就行
结果是:
console.log(1 + true); // 2 console.log({} + {}); // "[object Object][object Object]" console.log(new Date(2017, 04, 21) + 1) // "Sun May 21 2017 00:00:00 GMT+0800 (CST)1"
以上的运算都是在 console.log
中进行,若是你直接在 Chrome
或者 Firebug
开发工具中的命令行直接输入,你也许会惊讶的看到一些结果的不一样,好比:
咱们刚才才说过 {} + []
的结果是 "[object Object]"
呐,这怎么变成了 0
了?
不急,咱们尝试着加一个括号:
结果又变成了正确的值,这是为何呢?
其实,在不加括号的时候,{}
被当成了一个独立的空代码块,因此 {} + []
变成了 +[]
,结果就变成了 0
一样的问题还出如今 {} + {}
上,并且火狐和谷歌的结果还不同:
> {} + {} // 火狐: NaN // 谷歌: "[object Object][object Object]"
若是 {}
被当成一个独立的代码块,那么这句话至关于 +{}
,至关于 Number({})
,结果天然是 NaN
,但是 Chrome
却在这里返回了正确的值。
那为何这里就返回了正确的值呢?我也不知道,欢迎解答~
"=="
用于比较两个值是否相等,当要比较的两个值类型不同的时候,就会发生类型的转换。
关于使用"=="进行比较的时候,具体步骤能够查看规范11.9.5:
当执行x == y 时:
若是x与y是同一类型:
x是数字:
以为看规范判断太复杂?咱们来分几种状况来看:
console.log(null == undefined);
看规范第二、3步:
- x是null而且y是undefined,返回true
- x是undefined而且y是null,返回true
因此例子的结果天然为 true
。
这时候,咱们能够回想在《JavaScript专题之类型判断(上)》中见过的一段 demo
,就是编写判断对象的类型 type
函数时,若是输入值是 undefined
,就返回字符串 undefined
,若是是 null
,就返回字符串 null
。
若是是你,你会怎么写呢?
下面是 jQuery 的写法:
function type(obj) { if (obj == null) { return obj + ''; } ... }
console.log('1' == 1);
结果确定是true,问题在因而字符串转化成了数字和数字比较仍是数字转换成了字符串和字符串比较呢?
看规范第四、5步:
4.x是数字,y是字符串,判断x == ToNumber(y)5.x是字符串,y是数字,判断ToNumber(x) == y
结果很明显,都是转换成数字后再进行比较
console.log(true == '2')
当要判断的一方出现 false
的时候,每每最容易出错,好比上面这个例子,凭直觉应该是 true
,毕竟 Boolean('2')
的结果但是true,但这道题的结果倒是false。
归根到底,仍是要看规范,规范第六、7步:
6.x是布尔值,判断ToNumber(x) == y7.y是布尔值,判断x ==ToNumber(y)
当一方出现布尔值的时候,就会对这一方的值进行ToNumber处理,也就是说true会被转化成1,
true == '2'
就至关于 1 == '2'
就至关于 1 == 2
,结果天然是 false
。
因此当一方是布尔值的时候,会对布尔值进行转换,由于这种特性,因此尽可能少使用 xx == true
和 xx == false
的写法。
好比:
// 不建议 if (a == true) {} // 建议 if (a) {} // 更好 if (!!a) {}
console.log( 42 == ['42'])
看规范第八、9步:
- x不是字符串或者数字,y是对象,判断x == ToPrimitive(y)
- x是对象,y不是字符串或者数字,判断ToPrimitive(x) == y
以这个例子为例,会使用 ToPrimitive
处理 ['42']
,调用valueOf
,返回对象自己,再调用 toString
,返回 '42'
,因此
42 == ['42']
至关于 42 == '42'
至关于42 == 42
,结果为 true
。
到此为止,咱们已经看完了第二、三、四、五、六、七、八、9步,其余的一律返回 false。
再多举几个例子进行分析:
console.log(false == undefined)
false == undefined
至关于 0 == undefined
不符合上面的情形,执行最后一步 返回 false
console.log(false == [])
false == []
至关于 0 == []
至关于 0 == ''
至关于 0 == 0
,结果返回 true
console.log([] == ![])
首先会执行 ![]
操做,转换成 false,至关于 [] == false
至关于 [] == 0
至关于 '' == 0
至关于 0 == 0
,结果返回 true
最后再举一些会让人踩坑的例子:
console.log(false == "0") console.log(false == 0) console.log(false == "") console.log("" == 0) console.log("" == []) console.log([] == 0) console.log("" == [null]) console.log(0 == "\n") console.log([] == 0)
以上均返回 true
除了这两种情形以外,其实还有不少情形会发生隐式类型转换,好比if
、? :
、&&
等状况,但相对来讲,比较简单,就再也不讲解。
JavaScript 深刻系列目录地址:https://github.com/mqyqingfen...
JavaScript 深刻系列预计写十五篇左右,旨在帮你们捋顺JavaScript底层知识,重点讲解如原型、做用域、执行上下文、变量对象、this、闭包、按值传递、call、apply、bind、new、继承等难点概念。
若是有错误或者不严谨的地方,请务必给予指正,十分感谢。若是喜欢或者有所启发,欢迎 star,对做者也是一种鼓励。
如今是校招季,淘系前端正在帮助21届同窗们收割大厂offer,专门建立了交流群,能够在这里提问题,交流面试经验,这里也提供了简历辅导和答疑解惑等服务,加淘小招微信邀你入群,微信号 taoxiaozhao233