【问题标题】:How does Javascript implement date comparison operator?Javascript如何实现日期比较运算符?
【发布时间】:2017-10-06 07:22:10
【问题描述】:

This answer 说,

Date object 会做你想做的事 - 为每个日期构造一个,然后使用 ><<=>= 比较它们。

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

  • 这是特定于浏览器的行为,还是该语言的标准特性?
  • 如果 Date 是 javascript“对象”,并且 javascript 不支持运算符重载,那么 ><<=>= 运算符在 Date 对象上的这种行为是如何实现的?我的意思是,它是否在Date.prototype 上定义,是否因为定义了一些隐式转换(例如从对象到数字或字符串)而发生,它是添加到 Javascript 语言解释器/运行的 Date 对象的特例吗? -时间,还是什么?

【问题讨论】:

    标签: javascript datetime operator-overloading operators


    【解决方案1】:

    每当您使用通常期望数字(加法、减法、较大/较小比较)的对象时,都会调用 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();
    

    【讨论】:

    【解决方案2】:

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

    这是一个标准功能。

    如果Date 是一个javascript“对象”,并且javascript 不支持运算符重载,那么Date 上的&gt;&lt;&lt;=&gt;= 运算符的这种行为如何?对象实现了吗?

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

    特别是,Date 通过返回其基础时间值(自 1970 年 1 月 1 日格林威治标准时间午夜以来的毫秒数)来实现 valueOf。所以date1 &gt;= 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 默认为字符串。这过去只是内置到规范操作的逻辑中(DateSymbol 当时不存在),但现在它通过 Symbol.toPrimitive 方法处理,对象可以覆盖该方法以提供自己的处理被转换为原语的处理。

    如果我们希望 MyThing 默认为字符串而不是像 Date 那样的数字,我们将添加 Symbol.toPrimitive 方法(我还添加了 console.logs 到 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 现在是如何进行字符串连接的,在第一个 sn-p 中它是在进行加法。那是因为我们将默认行为更改为更喜欢字符串而不是数字。

    【讨论】:

      猜你喜欢
      • 2018-03-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多