-
Notifications
You must be signed in to change notification settings - Fork 4.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
JavaScript深入之头疼的类型转换(下) #164
Comments
Null与数字,第2步, |
!!!正在整理类型转换,大大就更新了! |
大大,==相等里面规范8、9翻译错了,应该是“是字符串或数字” |
想问一下if([]){console.log("kkk")}里面又是什么转换过程呢?如果是要按false == [] 的话,后面的打印就不会执行,但是实际上后面的语句块的内容会执行 |
!! 哪位大哥给一个比较清晰的分析,是不是用到了一元操作符转换,我觉得!这个操作符考题还挺多的 |
@mqyqingfeng 大大,console.log(0 == "\n")为什么是等于true?Number('\n')没搞明白为什么等于0,不是说如果有一个字符不是数字,结果都会返回 NaN么?为啥Number('\n')不是等于NaN |
我比较模糊,怎么判断先用valueOf还是toString |
@zh-lc 先调 valueOf,如果 valueOf 方法返回的值转 Number 后是 NaN 的话再调用 toString |
console.log(null + 1);
第二条 写错了 rprim = 1 |
@jjaimm |
[] 转换成boolean是true 只有 6 种值可以被转换成 false,其他都会被转换成 true。 |
|
!只是转化为Boolean然后取非。!!取非再取非,就相当于只是做了个类型转换 |
请问 console.log("" == [null]) 为什么是true啊??? 换句话说,为什么 ToPrimitive([null]) 结果是"" ????? |
@hanqizheng 抽象操作ToPrimitive会首先检查该值是否有valueOf()方法。如果有并且返回基本类型值,就使用该值进行强制类型转换,如果没有就使用toString()的返回值来进行强制类型转换。如果valueOf()和ToString()都不返回基本类型值,会产生TypeEror错误。 |
@Zshuhao 谢谢 |
这个跟类型转换没啥关系。 是各个浏览器处理 |
对着规范看头头是道,可是我记不住啊 |
chrome里:
|
我建议你直接看ES规范文档里列出来的StringNumericLiteral语法,String转Number本来就是一件很复杂的事情,不知道从哪个博客传出来的字母和数字混合就直接 |
我也发现这个问题了 |
大佬这里是不是打错了,我看了规范原文是这样的:
是不是应该写成:如果x是字符串或数字? |
http://yanhaijing.com/es5/#203 最后两条是不是写错了,应该是 x是字符串或者数字且y是对象,判断x == ToPrimitive(y) 规范 |
我觉得这里火狐的结果是对的,Chrome 返回 |
请问==的规范里1.iii.f这条是不是少了个条件,直接就“返回false”了 |
应该是 if (condition) { } 中的 condition 会被隐式转换为 Boolean 类型,Boolean([]) 为 true。 |
|
这里 Date 使用的是 toString,规范里有讲到 |
这个规则是不是可以总结成: 对象会优先转化成数字或字符串(根据判断的另一个数据类型)再进行比较; |
|
if 的转换规则和 == 不一样,if(xxx) 你可以看成 Boolean(xxx) |
关于 {} + {} 浏览器不同的输出,我刚好研究了下
故在chrome下{} + {} 即是({} + {}) |
|
前言
举个例子:
在 JavaScript 中,这是完全可以运行的,不过你有没有好奇,为什么 1 和 '1' 分属不同的数据类型,为什么就可以进行运算呢?
这其实是因为 JavaScript 自动的将数据类型进行了转换,我们通常称为隐式类型转换。但是我们都知道,
+
运算符既可以用于数字加法,也能用于字符串拼接,那在这个例子中,是将数字1
转成字符串'1'
,进行拼接运算?还是将字符串'1'
转成数字1
,进行加法运算呢?先卖个关子,虽然估计你也知道答案。今天,我们就常见的隐式类型转化的场景进行介绍。
一元操作符 +
当 + 运算符作为一元操作符的时候,查看 ES5规范1.4.6,会调用
ToNumber
处理该值,相当于Number('1')
,最终结果返回数字1
。那么下面的这些结果呢?
既然是调用
ToNumber
方法,回想《JavaScript 深入之头疼的类型转换(上)》中的内容,当输入的值是对象的时候,先调用ToPrimitive(input, Number)
方法,执行的步骤是:obj
为基本类型,直接返回valueOf
方法,如果返回一个原始值,则JavaScript
将其返回。toString
方法,如果返回一个原始值,则JavaScript
将其返回。JavaScript
抛出一个类型错误异常。以
+[]
为例,[]
调用valueOf
方法,返回一个空数组,因为不是原始值,调用toString
方法,返回""
。得到返回值后,然后再调用
ToNumber
方法,""
对应的返回值是0
,所以最终返回0
。剩下的例子以此类推。结果是:
二元操作符 +
规范
现在
+
运算符又变成了二元操作符,毕竟它也是加减乘除中的加号1 + '1'
我们知道答案是 '11',那null + 1
、[] + []
、[] + {}
、{} + {}
呢?如果要了解这些运算的结果,不可避免的我们要从规范下手。
规范地址:http://es5.github.io/#x11.6.1
不过这次就不直接大段大段的引用规范了,直接给大家讲简化后的内容。
到底当执行
+
运算的时候,会执行怎样的步骤呢?让我们根据规范11.6.1
来捋一捋:当计算 value1 + value2时:
规范的内容就这样结束了。没有什么新的内容,
ToString
、ToNumber
、ToPrimitive
都是在《JavaScript 深入之头疼的类型转换(上)》中讲到过的内容,所以我们直接进分析阶段:让我们来举几个例子:
1.Null 与数字
按照规范的步骤进行分析:
接下来:
ToNumber(null)
的结果为0,(回想上篇 Number(null)),ToNumber(1)
的结果为 1所以,
null + 1
相当于0 + 1
,最终的结果为数字1
。这个还算简单,看些稍微复杂的:
2.数组与数组
依然按照规范:
所以,
[] + []
相当于"" + ""
,最终的结果是空字符串""
。看个更复杂的:
3.数组与对象
按照规范:
所以,
[] + {}
相当于"" + "[object Object]"
,最终的结果是 "[object Object]"。下面的例子,可以按照示例类推出结果:
结果是:
注意
以上的运算都是在
console.log
中进行,如果你直接在Chrome
或者Firebug
开发工具中的命令行直接输入,你也许会惊讶的看到一些结果的不同,比如:我们刚才才说过
{} + []
的结果是"[object Object]"
呐,这怎么变成了0
了?不急,我们尝试着加一个括号:
结果又变成了正确的值,这是为什么呢?
其实,在不加括号的时候,
{}
被当成了一个独立的空代码块,所以{} + []
变成了+[]
,结果就变成了 0同样的问题还出现在
{} + {}
上,而且火狐和谷歌的结果还不一样:如果
{}
被当成一个独立的代码块,那么这句话相当于+{}
,相当于Number({})
,结果自然是NaN
,可是Chrome
却在这里返回了正确的值。那为什么这里就返回了正确的值呢?我也不知道,欢迎解答~
== 相等
规范
"=="
用于比较两个值是否相等,当要比较的两个值类型不一样的时候,就会发生类型的转换。关于使用"=="进行比较的时候,具体步骤可以查看规范11.9.5:
当执行x == y 时:
如果x与y是同一类型:
x是null并且y是undefined,返回true
x是undefined并且y是null,返回true
x是数字,y是字符串,判断x == ToNumber(y)
x是字符串,y是数字,判断ToNumber(x) == y
x是布尔值,判断ToNumber(x) == y
y是布尔值,判断x ==ToNumber(y)
x是字符串或者数字,y是对象,判断x == ToPrimitive(y)
x是对象,y是字符串或者数字,判断ToPrimitive(x) == y
返回false
觉得看规范判断太复杂?我们来分几种情况来看:
1. null和undefined
看规范第2、3步:
所以例子的结果自然为
true
。这时候,我们可以回想在《JavaScript专题之类型判断(上)》中见过的一段
demo
,就是编写判断对象的类型type
函数时,如果输入值是undefined
,就返回字符串undefined
,如果是null
,就返回字符串null
。如果是你,你会怎么写呢?
下面是 jQuery 的写法:
2. 字符串与数字
结果肯定是true,问题在于是字符串转化成了数字和数字比较还是数字转换成了字符串和字符串比较呢?
看规范第4、5步:
结果很明显,都是转换成数字后再进行比较
3. 布尔值和其他类型
当要判断的一方出现
false
的时候,往往最容易出错,比如上面这个例子,凭直觉应该是true
,毕竟Boolean('2')
的结果可是true,但这道题的结果却是false。归根到底,还是要看规范,规范第6、7步:
当一方出现布尔值的时候,就会对这一方的值进行ToNumber处理,也就是说true会被转化成1,
true == '2'
就相当于1 == '2'
就相当于1 == 2
,结果自然是false
。所以当一方是布尔值的时候,会对布尔值进行转换,因为这种特性,所以尽量少使用
xx == true
和xx == false
的写法。比如:
4. 对象与非对象
看规范第8、9步:
以这个例子为例,会使用
ToPrimitive
处理['42']
,调用valueOf
,返回对象本身,再调用toString
,返回'42'
,所以42 == ['42']
相当于42 == '42'
相当于42 == 42
,结果为true
。到此为止,我们已经看完了第2、3、4、5、6、7、8、9步,其他的一概返回 false。
其他
再多举几个例子进行分析:
false == undefined
相当于0 == undefined
不符合上面的情形,执行最后一步 返回false
false == []
相当于0 == []
相当于0 == ''
相当于0 == 0
,结果返回true
首先会执行
![]
操作,转换成 false,相当于[] == false
相当于[] == 0
相当于'' == 0
相当于0 == 0
,结果返回true
最后再举一些会让人踩坑的例子:
以上均返回 true
其他
除了这两种情形之外,其实还有很多情形会发生隐式类型转换,比如
if
、? :
、&&
等情况,但相对来说,比较简单,就不再讲解。深入系列
JavaScript 深入系列目录地址:https://github.com/mqyqingfeng/Blog
JavaScript 深入系列预计写十五篇左右,旨在帮大家捋顺JavaScript底层知识,重点讲解如原型、作用域、执行上下文、变量对象、this、闭包、按值传递、call、apply、bind、new、继承等难点概念。
如果有错误或者不严谨的地方,请务必给予指正,十分感谢。如果喜欢或者有所启发,欢迎 star,对作者也是一种鼓励。
The text was updated successfully, but these errors were encountered: