是什么让新的Date() / 1000成为一个有效的javascript

What makes new Date() / 1000 a valid javascript?

本文关键字:一个 javascript 有效 Date 是什么 1000成      更新时间:2023-09-26

为什么我可以将对象"除以"一个数字?

更新
延迟鉴于我的回答包含一些不完整的信息,有时甚至是完全错误的信息,我认为最好纠正我的错误。虽然晚了,但这里是:

几乎所有的 JS 对象都有 23 个共同的方法:valueOf()如果是 date 对象,它会映射回返回一个数字的 getTime() 方法。这个数字是什么,是自 1970 年 1 月 1 日以来的毫秒数,许多编程语言使用此日期作为其日期的基础。它被称为Unix时间戳,日期称为Unix纪元。如果你想知道。
另一种方法是 toString ,它返回一个字符串(显然)。
第三种方法是hasOwnProperty,这可以追溯到原型链中Object.prototype,但这对这个问题并不重要。

每当你比较 2 个值(对象与否)时,JS 都会强制两个操作数的类型,以便可以安全地比较这两个值(例如,1 == '1'强制字符串'1'Number)。
当对象或基元值连接成 stirng 时,或者当表达式被计算为单数值时(例如,在您的控制台中,键入 new Date; ,您将明白我的意思)。
Date对象的默认行为是强制转换为字符串,调用 toString 方法。

因此,Date实例没有什么不同。它们是对象,这意味着变量的值将是对对象的引用。但是,在您的表达式/语句中,您在对象上使用算术运算符(/)。在这种情况下,字符串没有多大意义,因此 JS 回退到 valueOf 方法(有点像,Date 可以通过多种方式强制为数字)。这确实会产生一个Number,可以毫不费力地划分。
当使用比较运算符><<=>=时,可以预期(并且确实可以观察到)相同的行为。
这意味着比较日期并使用它们来生成输出在大多数情况下是一件麻烦事:

var d1 = new Date();
var d2 = new Date(1234567890123);
if (d1 > d2)
{
   //do stuff
}

完整编写时,这是:

Date.prototype.valueOf = Date.prototype.getTime; //<-- this isn't how its done, but think of the valueOf method as doing something similar
if (d1.getTime() > d2.getTime()) //OR:
if (d1.valueOf() > d2.valueOf())

除了比较之外,还有其他优点:

var d3 = new Date(d1 - 1000); //new date, 1 second before d1

但是有一个权衡/陷阱:
与 JS 中的所有对象一样,使用 ===== 进行相等性检查起初有点奇怪:

var a = new Date();
var b = new Date(a.valueOf());
console.log(a.toString() === b.toString());//true
console.log(a.valueOf() === b.valueOf());//true, to the milisecond
console.log(a == b);//false!
console.log(a === b);//false!!

就像我说的:赋值对象的变量实际上并不保存该对象的值,而是引用它。由于 ab 都引用同一对象的不同实例,因此它们不相等。也因为它们都是对象(同一类型),所以没有类型强制发生。
把它想象成2栋房子,除了地址之外,各方面都是100%相等的。如果没有胁迫,你实际上是在说这样的话:
"小说街1号和小说街2号有一所房子。这两所房子是平等的吗?答案是响亮的否定。

要解决此问题,您必须明确要求JS通过手动将它们强制为另一种类型来比较这些房屋的外观。这比听起来容易得多:

console.log(a.valueOf() == b.valueOf());//true
//or shorter, still:
console.log(+(a) == +(b));
//coerce to strings, either call toString, or:
console.log((''+a) == (''+b));

同样,乍一看这似乎很愚蠢,但这样,您至少可以测试两个变量是否确实引用了相同的实例。假设我们有 2 个对象占用内存,当我们实际上只需要 1 个对象时,我们可以释放对其中一个实例的引用进行 GC'ed:

if (a !== b && +(a) === +(b))
{//their values are the same, but different instances
    b = a;//now b references the same object as a
}
console.log(a === b);//true
console.log(+(a) === +(b));// true again

请注意,现在仍然有一些奇怪的东西特别影响Date对象。尝试猜测以下语句将记录的内容:

a.setTime(a.getTime() + 1000);//add 1 second
console.log(a == (b + 1000));
console.log(a === (b + 1000));
console.log((a-1000) == b);
console.log((a-1000) === +b);

答案是:假,假,假,真。怎么来了?
第一种情况很简单:+运算符重载,它还连接字符串,Date对象的默认行为是toString自身,因此b+1000被计算为 b.toString() + '1000'
接下来,使用类型和值检查===几乎总是错误的,因为没有强制行为发生。
然后,通过使用重载的 - 算术运算符减去 1000,意味着左操作数仍将计算为一个数字。但是,正确的操作数仍将恢复到其被强制到字符串的错误行为。它们是不平等的。
最后一个示例显式将右操作数强制为数字,并生成 true。

要在上述所有情况下获得true,请写以下内容

console.log(+a == (+b + 1000));
console.log(+a === (+b + 1000));
console.log((a-1000) == +b);
console.log((a-1000) === +b);

只需显式强制Date实例,您应该没问题

对对象执行算术运算时,将隐式调用其valueOf函数。

尝试以下操作以获得可以实际划分的对象:

function Foo() {
    this.valueOf = function() {
        return 500;
        };
    }
var bar = new Foo();
console.log(bar/1000); // -> 0.5

因为当您使用除法运算符时,new Date()将被错误地转换为一个数字(表示从 1970 年 1 月 1 日开始的此日期的总毫秒数)。+运算符将不起作用,因为字符串中的+意味着连接,而不是总和,当您尝试对日期求和时,它不会返回毫秒,而是返回该日期的 toString(),但*将起作用,因为 String 没有 * 运算符。例如,尝试new Date() * 2

有关 Date 全局对象的更多详细信息,请查看此处:https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date

编辑:我说当日期在带有/的表达式中时,日期将被转换为字符串,我当然错了。我已经纠正了答案。下面有一些评论可以进一步澄清我的答案。字符串到数字的行为仍然有效,即表示有效数字的字符串可以乘、除和减,但不能相加,因为 sum 运算符用于连接字符串。看一看:

console.log( "10" + "1" );
console.log( "10" - "1" );
console.log( "10" * "2" );
console.log( "10" / "3" );
console.log( 10 + "1" );
console.log( 10 - "1" );
console.log( 10 * "2" );
console.log( 10 / "3" );
console.log( "10" + 1 );
console.log( "10" - 1 );
console.log( "10" * 2 );
console.log( "10" / 3 );

除法前日期对象将转换为数字,这将给出从 1970 年 1 月 1 日开始的毫秒

new Date()/1000 => Number(new Date()) / 1000 = some number

大多数语言实际上在他们自己的内部语言中将日期表示为一个数字。Javascript 使用的约定是自 1970 年 1 月 1 日以来的毫秒数,许多其他语言也有类似的约定。这与您可以简单地以计时方法的工作方式相互减去日期的原因相同。