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

时间:2012-08-17 14:06:20

标签: javascript

为什么我可以用数字“划分”一个对象?

5 个答案:

答案 0 :(得分:5)

延迟更新
鉴于我的答案包含一些不完整的和 - 时间 - 完全错误的信息,我认为最好纠正我的错误。虽然很晚,但这里有:

几乎所有JS对象都有 2 3 方法:valueOf()如果是日期对象,它会映射回来到getTime()方法,返回一个数字。这个数字是自1970年1月1日以来的毫秒数,许多编程语言使用此日期来确定日期。它被称为Unix时间戳,日期称为Unix Epoch。万一你想知道。
另一种方法是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:

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被评估为{ {1}}。
接下来,使用类型和值检查b.toString() + '1000'几乎总是假的,因为没有强制进行。
然后,通过使用 not 重载===算术运算符减去1000意味着左操作数仍将被计算为数字。然而,正确的操作数仍将恢复为强制转换为字符串的行为。他们不平等 最后一个示例显式地将右操作数强制转换为数字,并产生true。

要在上述所有情况下获得-,这里是写什么

true

只需明确强制您的console.log(+a == (+b + 1000)); console.log(+a === (+b + 1000)); console.log((a-1000) == +b); console.log((a-1000) === +b); 个实例,就可以了。

答案 1 :(得分:4)

因为当您使用除法运算符时,new Date()将被明确转换为数字(表示从1970年1月1日开始的此日期的总毫秒数)。 +运算符不起作用,因为字符串中的+表示连接,而不是求和,当您尝试对Date求和时,它不会返回毫秒,而是返回该日期的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 );

答案 2 :(得分:2)

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

尝试以下内容以获得一个可以实际划分的对象:

function Foo() {

    this.valueOf = function() {
        return 500;
        };

    }

var bar = new Foo();
console.log(bar/1000); // -> 0.5

答案 3 :(得分:1)

在分割日期之前,对象将被转换为数字,该数字将给出1970年1月1日以来的毫秒数

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

答案 4 :(得分:0)

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