![a141c4ec4a2d391e626f3ab9c15620d6.png](https://img-blog.csdnimg.cn/img_convert/a141c4ec4a2d391e626f3ab9c15620d6.png)
认真的小伙伴应该发现了,在上一章的代码里面高频出现了var now = +new Date()。那爱动脑筋的小伙伴就会问,这里为什么要有个加号?这个加号又有什么作用呢?
简单的说,这个是转时间戳的方法
但是,真实的变化是什么样的呢?
这是隐式转换
我们先看看ECMAScript规范对一元运算符的规范:
一元+ 运算符
一元+运算符将其操作数转换为Number类型并反转其正负。注意负的+0产生-0,负的-0产生+0。
产生式 UnaryExpression : - UnaryExpression 按照下面的过程执行 :
- 令 expr 为解释执行 UnaryExpression 的结果 .
- 令 oldValue 为 ToNumber(GetValue(expr)).
- 如果 oldValue is NaN ,return NaN.
- 返回 oldValue 取负(即,算出一个数字相同但是符号相反的值)的结果。
+new Date()相当于 ToNumber(new Date())
我们再来看看ECMAScript规范对ToNumber的定义:
![4eab04d98b00f934a562e4cb00ce56c1.png](https://img-blog.csdnimg.cn/img_convert/4eab04d98b00f934a562e4cb00ce56c1.png)
我们知道new Date()是个对象,满足上面的ToPrimitive(),所以进而成了ToPrimitive(new Date())
接着我们再来看看ECMAScript规范对ToPrimitive的定义,一层一层来,抽丝剥茧。
![05d43625cebb9e2fbd58257323be47f2.png](https://img-blog.csdnimg.cn/img_convert/05d43625cebb9e2fbd58257323be47f2.png)
这个ToPrimitive可能不太好懂,我给你解释一下吧:
ToPrimitive(obj,preferredType)JS引擎内部转换为原始值ToPrimitive(obj,preferredType)函数接受两个参数 第一个obj为被转换的对象 第二个preferredType为希望转换成的类型(默认为空,接受的值为Number或String)在执行ToPrimitive(obj,preferredType)时如果第二个参数为空并且obj为Date的实例时,此时preferredType会被设置为String,其他情况下preferredType都会被设置为Number如果preferredType为Number,ToPrimitive执行过程如下:1. 如果obj为原始值,直接返回;2. 否则调用 obj.valueOf(),如果执行结果是原始值,返回之;3. 否则调用 obj.toString(),如果执行结果是原始值,返回之;4. 否则抛异常。如果preferredType为String,将上面的第2步和第3步调换,即:1. 如果obj为原始值,直接返回;2. 否则调用 obj.toString(),如果执行结果是原始值,返回之;3. 否则调用 obj.valueOf(),如果执行结果是原始值,返回之;4. 否则抛异常。
![5779b87860008d7fc63092af5251a856.png](https://img-blog.csdnimg.cn/img_convert/5779b87860008d7fc63092af5251a856.png)
首先我们要明白 obj.valueOf() 和 obj.toString() 还有原始值分别是什么意思,这是弄懂上面描述的前提之一:
toString用来返回对象的字符串表示。
var obj = {};console.log(obj.toString()); // [object Object]var arr2 = [];console.log(arr2.toString()); // ""空字符串 var date = new Date();console.log(date.toString()); // Tue Jul 30 2019 09:44:17 GMT+0800 (中国标准时间)
valueOf方法返回对象的原始值,可能是字符串、数值或bool值等,看具体的对象。
var obj = { name: "obj"};console.log(obj.valueOf());//Object {name: "obj"}var arr1 = [1];console.log(arr1.valueOf());//[1]var date = new Date();console.log(date.valueOf());//1564451057792如代码所示,三个不同的对象实例调用valueOf返回不同的数据
原始值指的是['Null','Undefined','String','Boolean','Number','Symbol']6种基本数据类型之一
最后分解一下其中的过程:
+new Date():
1.运算符new的优先级高于一元运算符+,所以过程可以分解为:
var time=new Date();
+time
2.根据上面提到的规则相当于:ToNumber(time)
3.time是个日期对象,根据ToNumber的转换规则,所以相当于:ToNumber(ToPrimitive(time))
4.根据ToPrimitive的转换规则:ToNumber(time.valueOf()),time.valueOf()就是 原始值 得到的是个时间戳,假设time.valueOf()=1503479124652
5.所以ToNumber(1503479124652)返回值是1503479124652这个数字。
6.分析完毕,从原理得出结果,而不是从浏览器输出的结果来解释结果。用结论解释结论,会忽略很多细节
好了,到这里,大家应该对标题中的问题有了一个满意的答案了吧,但是也有细心的小伙伴发现了“问题”,既然“在执行ToPrimitive(obj,preferredType)时如果第二个参数为空并且obj为Date的实例时,此时preferredType会被设置为String",那么就会先调用obj.toString(),返回的就是一个字符串,那就和我们期望的时间戳不一样了
如果你心中有此一问,恭喜你,你马上会找到答案了
![551eee5e0fa273fa00ab0125b33f6197.png](https://img-blog.csdnimg.cn/img_convert/551eee5e0fa273fa00ab0125b33f6197.png)
所以,你明白了吗?
参考文章:
https://github.com/jawil/blog/issues/5