为什么我可以使用Date对象进行数学运算?

时间:2018-06-11 08:03:47

标签: javascript

当我减去两个Date对象时:

const startTime = new Date();
await someAsyncStuff();
const endTime = new Date();

const elapsedTime = endTime - startTime;
console.log(`The async stuff took ${elapsedTime} ms`);

为什么Date对象最终被强制转换为毫秒,然后被减去?我知道他们这样做了,但我无法弄清楚导致这种情况的实际事件顺序是什么。

4 个答案:

答案 0 :(得分:5)

JavaScript对象可以定义方法valueOf,对于Date个对象,将时间转换为纪元毫秒。然后,在将对象转换为基元时,JavaScript将自动使用此函数,仅在某些情况下。

令人困惑的是,JavaScript对象还可以定义方法toString,该方法将对象转换为String(Date提供自定义实现)。作为@baao mentions in his answer,由于类型的自动转换,在对对象进行“算术”时可能会出现一些问题。

JavaScript是否选择使用toString vs valueOf取决于上下文。有关详细信息,请参阅this questionthe overall spec for addition(和subtraction)和the specific spec for Datesmdn link)和@baao's answer以获取更深入的信息看。但总的来说,Date(与大多数其他对象不同)默认为字符串转换,但由于减法需要两个数字才有意义,因此它将日期转换为数字。

明确定义行为通常是一个好主意,在这种情况下使用valueOfgetTimetoString来使代码不那么模糊。

另见:

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