Javascript如何实现日期比较运算符?

时间:2017-05-08 10:17:49

标签: javascript datetime operator-overloading operators

This answer说,

  

Date object会按照您的意愿行事 - 为每个日期构建一个,然后使用><<=>=进行比较。

我没有在引用页面上看到此功能。

  • 这是特定于浏览器的行为,还是该语言的标准功能?
  • 如果日期是javascript&#34;对象&#34;,并且javascript不支持运算符重载,那么><,{{1实现了Date对象的{}或<=运算符?它的意思是,它是在>=上定义的,它是否因为某些隐式转换被定义(例如从一个对象到一个数字或一个字符串)而发生,是否是添加到Javascript语言解释器的Date对象的特例/运行时,还是什么?

2 个答案:

答案 0 :(得分:2)

每当您想要一个Object为Number时,就会调用 valueOf 方法:

{valueOf:()=>2}.valueOf() //2
//or not explicitly called:
+{valueOf:()=>2} //2
//using the compare operator:
{valueOf:()=>2}<{valueOf:()=>3}//true as  2<3

因此,当您比较日期时,这也会发生。由于 Date.prototype.valueOf 方法返回自1970年以来的毫秒数,您可以使用它来比较两个日期......

new Date().valueOf();
//or
+new Date(); 
//or
new Date()<new Date();

答案 1 :(得分:2)

<块引用>

这是特定于浏览器的行为,还是语言的标准功能?

这是标准功能。

<块引用>

如果 Date 是一个 javascript“对象”,并且 javascript 不支持运算符重载,那么 ><<=>= 运算符对 Date 对象实施了吗?

因为 Date 实现 valueOfSymbol.toPrimitive 的方式(toString 是相关的,但与您提到的特定运算符无关)。这三个方法在规范中通过OrdinaryToPrimitive抽象操作将对象隐式转换为原始值的过程中使用,运算符在需要原始值(如字符串或数字)时使用它,但它们接收一个对象。

特别是,Date 通过返回其基础时间值(格林威治标准时间 1970 年 1 月 1 日午夜以来的毫秒数)来实现 valueOf。所以 date1 >= date2 在每个日期上调用 valueOf,暗示首选数字,它从日期中获取时间值(一个数字),然后比较它们。更多内容如下。

此问题的副本:

<块引用>

我们可以为任何班级做吗?

是的,从 ES2015 开始,这一切都是标准的,Date 不再像以前那样特殊(它的特殊方式相对较小,更多内容见下文)。例如:

class MyThing {
    constructor(value) {
        this.value = value;
    }
    
    valueOf() {
        return this.value;
    }

    toString() {
        return String(this.value);
    }
}

const a = new MyThing(27);
const b = new MyThing(42);
console.log(`a < b? ${a < b}`);   // a < b? true
console.log(`b < a? ${b < a}`);   // b < a? false
console.log(`b - a = ${b - a}`);  // b - a = 15
console.log(`a + b = ${a + b}`);  // a + b = 69

(上面遗漏了 Date 的一些东西,稍后会更多。)

当操作符或类似操作需要将对象转换为原始类型时,它会使用对象的“转换为原始类型”操作,可选择提供有关其偏好的“提示”(字符串、数字或无偏好)。关系运算符更喜欢数字,所有纯数学运算符(如 -)也是如此。 + 运算符,既是加法又是字符串连接,不提供提示,因此使用对象的默认值。如果没有提示,几乎内置对象默认为数字; DateSymbol 默认为字符串。这曾经只是内置到规范操作的逻辑中(对于 Date; Symbol 当时不存在),但现在通过 Symbol.toPrimitive 方法处理,它是一个对象可以覆盖以提供其自己的转换为基元的处理。

如果我们希望 MyThing 默认为字符串而不是像 Date 那样的数字,我们会添加 Symbol.toPrimitive 方法(我还添加了 console.log valueOftoString 显示哪个用于操作):

class MyThing {
    constructor(value) {
        this.value = value;
    }
    
    valueOf() {
        console.log("valueOf");
        return this.value;
    }

    toString() {
        console.log("toString");
        return String(this.value);
    }

    [Symbol.toPrimitive](hint) {
        if (hint === "number") {
            return this.valueOf();
        }
        // "default" or "number"
        return this.toString();
    }
}

const a = new MyThing(27);
const b = new MyThing(42);
console.log(`a < b? ${a < b}`);   // a < b? true
console.log(`b < a? ${b < a}`);   // b < a? false
console.log(`b - a = ${b - a}`);  // b - a = 15
console.log(`a + b = ${a + b}`);  // a + a = "2742"

请注意 a + b 现在是如何进行字符串连接的,在第一个代码段中它进行的是加法。那是因为我们更改了默认行为,将字符串优先于数字。