当我减去两个Date对象时:
const startTime = new Date();
await someAsyncStuff();
const endTime = new Date();
const elapsedTime = endTime - startTime;
console.log(`The async stuff took ${elapsedTime} ms`);
为什么Date对象最终被强制转换为毫秒,然后被减去?我知道他们这样做了,但我无法弄清楚导致这种情况的实际事件顺序是什么。
答案 0 :(得分:5)
JavaScript对象可以定义方法valueOf
,对于Date
个对象,将时间转换为纪元毫秒。然后,在将对象转换为基元时,JavaScript将自动使用此函数,仅在某些情况下。
令人困惑的是,JavaScript对象还可以定义方法toString
,该方法将对象转换为String(Date
提供自定义实现)。作为@baao mentions in his answer,由于类型的自动转换,在对对象进行“算术”时可能会出现一些问题。
JavaScript是否选择使用toString
vs valueOf
取决于上下文。有关详细信息,请参阅this question,the overall spec for addition(和subtraction)和the specific spec for Dates(mdn link)和@baao's answer以获取更深入的信息看。但总的来说,Date
(与大多数其他对象不同)默认为字符串转换,但由于减法需要两个数字才有意义,因此它将日期转换为数字。
明确定义行为通常是一个好主意,在这种情况下使用valueOf
,getTime
或toString
来使代码不那么模糊。
另见:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/valueOf https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/valueOf
答案 1 :(得分:4)
javascript如何automatic type conversion - 就像算术运算一样(你在这里表现)。你很幸运,你已经减去,如果你已经添加它们,你最终会得到一个连续两个日期字符串的字符串,因为toPrimitive
(隐式调用)对日期有用。请考虑以下
// automatic casting
console.log("1" - "1"); // 0
// but
console.log("1" + "1"); // 11
// now with dates
// automatic casting
console.log(new Date() - new Date()); 0
console.log(new Date() + new Date()); // Mon Jun 11 2018 10:10:36 GMT+0200 (Mitteleuropäische Sommerzeit)Mon Jun 11 2018 10:10:36 GMT+0200 (Mitteleuropäische Sommerzeit)

additional operator上的规范有以下提示,可以进一步解释
除日期对象之外的所有本机ECMAScript对象都会处理缺少提示,就像提供了提示号一样;日期对象处理没有提示,就像给出了提示字符串一样。
JavaScript在使用算术运算符时将您的值转换为基元,此处调用的方法是
Date.prototype [ @@toPrimitive ] ( hint )
Date.prototype [ @@toPrimitive ] ( hint ) ECMAScript语言运算符调用此函数将Date对象转换为原始值。提示的允许值为"默认","数字"和"字符串"。日期对象在内置ECMAScript对象中是唯一的,因为它们处理"默认"等同于"字符串",所有其他内置ECMAScript对象处理"默认"等同于"数字"。
那就是说。您的代码工作原理的原因是subtraction执行的后续自动转换,它会提示toPrimitive
返回一个数字。
答案 2 :(得分:2)
等于endTime.getTime() - startTime.getTime()
正如你所说,他们施展到毫秒,这恰好表明了差异。
答案 3 :(得分:1)
这种情况正在发生,因为JS在执行此类操作时会通过方法valueOf请求Date对象的原语。 Date的对象overrides valueOf
方法,因此使用的值与getTime基本相同。
您也可以自己尝试:
const o = { valueOf: () => 10 };
console.log(o + 1) // 11