近日看到一篇叫做百度web前端面试经历(原文已佚,这篇也是转载)的文章,其中作者详细的描述了自己去百度web前端面试的经历,Interviewer问及问题的范围也十分广泛,有一定的参考价值。不过这篇文章的美中不足之处就在于,作者没有对问题给出一个合理的解释,有些面试的问题作者本身所知也并不详细。这里就写一篇小文章分析一下面试中提到的问题。
面试官:javascript的类型转换(比如"2"*1, "a"*1)。
我:javascript会调用valueOf来转换为一个基本数据类型,在这种情况下,如果javascript不能通过valueOf转成一个number,会尝试调用toString,然后再转。实在无法转就只能NaN了。
由于JS一切皆对象的基础理念,Object 在 JS中广泛存在,但JS的所有变量还是分为原始值和对象。JS的类型转换不仅仅是狭义意义上的原始值(即 string、int 和 boolean)之间的互相转换,按照犀牛书中所说,主要分为三个大类:
- 原始值转原始值
- 原始值转对象
- 对象转原始值
在此基础上,也有根据转换方式将其分为“显式转换”和“隐式转换”的说法,所谓的显示转换,即运用基本类型函数的构造函数(Number()
,String()
,Boolean()
,Object()
)对某个变量进行人为的强制类型转换;所谓的隐式转换,是指在进行运算时JavaScript进行自动的类型转换,如==
运算符、+
运算符等。其中有几个比较著名的隐式转换,可以作为类型转换的惯用方式:
x+'' //等价于 String(x)
+x //等价于 Number(x)
!!x //等价于 Boolean(x)
然后我们再来看一下,类型转换的三个大类。
-
原始值转原始值
相对简单,可以采用上面所述的显式或隐式的转换方式,在字符串、数字和布尔值之间进行转换。
但是这里有一些值得注意的转换,例如空字符串、正负0、
NaN
在转化为布尔值时均为false(注意字符串 'false' 转化为布尔值为真!),在一些情况下可以进行快速的判断;字符串如果不能转为数字,则转化为NaN
(undefined
也会转化为这个),而null
却可以转化为数字0;数字里的Infinity
和-Infinity
都可以转化为对应的字符串,转化为布尔值时也是true。 -
原始值转对象
这里实际上就是使用基本函数的构造函数,加上
new
运算符,生成一个对象。这里又几个巧妙的用法,比如数值可以用toString()
方法进行快速的进制转换;在我前几日写过的一篇小文:JavaScript绝句小研究中,绝句6中也展示了一个用toFixed()
函数进行位数截取的功能。 -
对象转原始值
对于对象转化为布尔值而言,比较简单:均为true(这一点和python又有不同,比如空数组和空对象,在JS中也视为true)。对于转化为数值和字符串:根据犀牛书中所说,所有的对象都继承了两个方法来进行到原始值的转换,一个是
toString
,一个是valueOf
,这两个方法顾名思义,一个是转化为字符串的,一个是转化为数值的。只是toString
的方法强大一些,基本上什么都能转;valueOf
相比之下弱一些,唯一能完整转换的对象就是把 Date() 对象转化为对应的时间戳(绝句的第二个)。那么作者在面试中说的正确与否呢?犀牛书里说,这里分为三个部分,
- 隐式转换:除Date外,统统是先
valueOf
、再toString
(Date 在+
和==
时优先转化为字串)。 - 显式对象转数值:对象转数值的方法,先尝试
valueOf
(如果能返回原始值就退出)、如果不行再尝试toString
,否则NaN。 - 显式对象转字符串:对象转字符串的过程恰好是反过来的,先尝试
toString
(能返回原始值就退出),再valueOf
,否则进行报错。
我们可以实际写一个小例子测试一下,这里我们用数组来表示一个对象,观察其类型转换:
Array.prototype.valueOf = function() {return 10} // 重写valueOf函数 Array.prototype.toString = function() {return '88'} // 重写toString函数 !![] // 结果为true,任意对象转换为布尔值均为真 [] + 1 // 结果为11,在隐式转换里,先valueOf,有原始值且能参与运算则直接返回 [] + '' // 结果为'10',隐式转换,虽然是要转换为字符串,但同样是先进行了valueOf Number([]) // 结果为11,显示转换,先进行valueOf String([]) // 结果为'88',显式转换,先进行toString Array.prototype.valueOf = null // 令valueOf失效 [] + 1 // 结果为'881',隐式转换valueOf不行后转到toString,得到原始值字符串直接返回 Number([]) // 同理,结果为88
- 隐式转换:除Date外,统统是先
所以实际上作者所说比较片面,实际上局限与隐式转换的情况——不过看面试官的提问,大概也就是要说道这点为止吧。经过上面的分析,其实有很多看起来头大的题目都可以迎刃而解,比如这道为什么 ++[[]][+[]]+[+[]] = 10?;但是在浏览 justjavac 的博客时还是发现了一个跟类型转换相关,但又有点蹊跷的题目:JavaScript中,{}+{}等于多少?,有兴趣的读者可以研究一下。
原文链接:http://www.ituring.com.cn/article/53351