感谢winter老师的分享,受益匪浅。
但是本文有两点是值得商榷的。
其一:
原文:Undefined 跟 null 有一定的表意差别,null表示的是:“定义了但是为空”。
私以为,undefined表示的是:“定义了但是为空”。而非null。
二:
原文:
var o = {
valueOf : () => {console.log("valueOf"); return {}},
toString : () => {console.log("toString"); return {}}
}
o + ""
// toString
// valueOf
// TypeError
很多朋友已经提出来了,应该是先执行valueof,再执行toString。
这个问题,可以从ecmascript规范中寻找答案:
规范指出,类型转换的内部实现是通过ToPrimitive ( input [ , PreferredType ] )方法进行转换的,这个方法的作用就是将input转换成一个非对象类型。
参数preferredType是可选的,它的作用是,指出了input被期待转成的类型。
如果不传preferredType进来,默认的是'number'。
如果preferredType的值是"string",那就先执行"toString", 后执行"valueOf"。否则,先执行"valueOf", 后执行"toString"。
由此可见,"toString", "valueOf"的执行顺序,取决于preferred的值。
规范原文请移步:http://www.ecma-international.org/ecma-262/#sec-toprimitive
再回到我们的例子
var o = {
valueOf : () => {console.log("valueOf"); return {}},
toString : () => {console.log("toString"); return {}}
}
o + ""
类型转换时,把对象o进行转换,调用toPrimitive方法,即toPrimitive(o[ , PreferredType ] )。关键的点是,preferredType是否被传值,传的是什么值?
我们再去看下规范,看看加法运算符的规则。
加法运算符运算过程中有两行代码很重要,如下
Let lprim be ? ToPrimitive(lval).
Let rprim be ? ToPrimitive(rval).
可以看出,调用ToPrimitive方法时,第二个参数是没有传参的。
所以preferredType取默认的值"number"。最终先执行"valueOf", 后执行"toString"。
个人愚见,如有纰漏,还请各位同仁指正。
展开
作者回复: 一、undefined确实是表示未定义,从字面即可看出来。
取JavaScript对象的未定义过的属性得到的都是undefined。
二、嗯,这个地方我确实写错了,等下改过来。