I have often seen the trick
after = +after;
to coerce the variable after to a number. Reading through the Node.JS source I found another method:
after *= 1; // coalesce to number or NaN
Are the two methods strictly equivalent in their behaviour?
Yes. Both Unary Operator + and Multiplicative Operators such as * (called from Compound Assignment op=) invoke the internal ToNumber algorithm.
You can even use a 3rd option by statically calling the Number constructor:
after = Number(after);
After a quick google to make sure my suspicions were true, I came to this conclusion. Using the + operator to convert to a number is faster, because no mathematical operations occur after type-casting, whereas using the *= approach means that after after is converted, it will be multiplied by 1.
Yes, however note that it is only the unary + operator that does this. I.e. 10 + "10" will give you "1010".
A perhaps less error prone option is to use what asm.js does:
10 + ("10"|0)
Although on the down-side it does require the brackets. It should be the fastest option in any case (probably equal to unary +).
Note: In some instances after = after-0 invokes different behaviour than after = after+0. I've noticed it with dates.
This is tested in Chrome v39 only:
var date = new Date(2000,0,1);
date += date; //"Sat Jan 01 2000 00:00:00 GMT+0000 (GMT Standard Time)Sat Jan 01 2000 00:00:00 GMT+0000 (GMT Standard Time)"
var date2 = new Date(2000,0,1);
date2 + 0; //"Sat Jan 01 2000 00:00:00 GMT+0000 (GMT Standard Time)0"
date2 - 0; //946684800000
date2 * 1; //946684800000
I don't know what is defined in the JS spec, but with dates, because both the date and the number can be cast to a string, and the + operator works on a string, then Chrome goes with a string concatenation. Because the - operator has no string equivalent, it falls back to number comparison.
I've found this useful when coercing dates into numbers for comparisons
Related
d = new Date();
d; // it is a string: Fri Apr 23 2021 10:30:34 GMT+0800(..)
d - 0; // it is a number: 1619145034656
d + 0; // it is a string: Fri Apr 23 2021 10:30:34 GMT+0800(..)0
d * 2; // it is a number: 3238290069312
d / 2; // it is a number: 809572517328
d.valueOf(); // it is a number: 1619145034656
d.toString(); // it is a string "Fri Apr 23 2021 10:30:34 GMT+0800 (...)"
I could accept all arithmetic but add(+), know '+' could be used for concating two string, but d.valueOf() is a number.
How Date objects know when use a string as it's value and when use number as it's value?
When operators like these are used, the specification runs a particular sequence of operations. If the operator used is +:
2. If opText is +, then
a. Let lprim be ? ToPrimitive(lval).
b. Let rprim be ? ToPrimitive(rval).
And calling ToPrimitive on a Date results in the string representation of the Date being returned.
In contrast, all of the other operators like - * / result in the other branch of the specification running:
3. NOTE: At this point, it must be a numeric operation.
4. Let lnum be ? ToNumeric(lval).
5. Let rnum be ? ToNumeric(rval).
...
9. Return ? operation(lnum, rnum).
The main difference is that + can be used to either add or concatenate. When either side is an object, it will cast the objects to strings, then concatenate. When any other operator is used, it will case the objects to numbers, then perform the appropriate arithmetic operation.
When ToPrimitive is called on a Date, the Date's ##toPrimitive method runs with no hint, which does:
If hint is string or default, ##toPrimitive tries to call the toString method. If the toString property does not exist, it tries to call the valueOf method and if the valueOf does not exist either, ##toPrimitive throws a TypeError.
As you can see, when called with no hint, the Date is cast to a string.
Let's assume I have a proper Date object constructed from the string: "Tue Jan 12 21:33:28 +0000 2010".
var dateString = "Tue Jan 12 21:33:28 +0000 2010";
var twitterDate = new Date(dateString);
Then I use the < and > less than and greater than comparison operators to see if it's more or less recent than a similarly constructed Date. Is the algorithm for comparing dates using those operators specified, or is it specifically unspecified, like localeCompare? In other words, am I guaranteed to get a more recent date, this way?
var now = new Date();
if (now < twitterDate) {
// the date is in the future
}
Relational operations on objects in ECMAScript rely on the internal ToPrimitive function (with hint number) that you can access, when it is defined, using valueOf.
Try
var val = new Date().valueOf();
You'll get the internal value of the date which is, as in many languages, the number of milliseconds since midnight Jan 1, 1970 UTC (the same that you would get using getTime()).
This means that you're, by design, ensured to always have the date comparison correctly working.
This article will give you more details about toPrimitive (but nothing relative to comparison).
Date values in Javascript are numbers, as stated in the ECMA Script specification. So the Date values are compared as numbers.
This is a demo of your code (I set twitterDate in the future).
(function(){
var dateString = "Tue Jan 12 21:33:28 +0000 2014";
var twitterDate = new Date(dateString);
var now = new Date();
if (now < twitterDate) {
document.write('twitterDate is in the future');
}
else
{
document.write('twitterDate is NOT in the future');
}
})()
I think yes. Using if (now < twitterDate), it evaluates to if (now.valueOf()<twitterDate.valueOf()). valueOf() delivers the number of milliseconds passed since 01/01/1970 00:00:00, so the comparison of those 2 numbers is valid.
check it like this
var then = new Date("Tue Jan 12 21:33:28 +0000 2010")
,now = new Date;
console.log(then.valueOf(),'::',now.valueOf(),'::',now<then);
//=> 1263332008000 :: 1352365105901 :: false
Consider the following code:
var a = new Date(someDateString);
var b = new Date(someOtherDateString);
console.log(b - a); // Outputs for example 3572, number of millisecs between the dates
Why does this work? This is an arithmetic operation on two objects. It looks suspiciously like operator overloading, known from C++ and other languages, but as far as I know, JavaScript won't get that before ECMAScript 7.
One would think the JS engine would turn it into something like
console.log(b.toString() - a.toString());
but this prints "NaN", as toString on a dateobject returns a string on the format
Mon Mar 23 2015 13:21:33 GMT+0100 (CET)
So, what magic makes this arithmetic possible? Can it be implemented on custom objects?
It converts them through .valueOf() not .toString(). Internally a date is stored as a number. The toString() method just formats it using a date formatting routine.
See The Subtraction Operator in the spec.
valueOf is called to fetch the numeric primitive of the date:
function o(i) {
this.valueOf = function() { return i; }
}
var a = new o(100);
var b = new o(42);
alert(a - b); // 58
A JS Date Object is just "a number of milliseconds".
"Zero time" starts at 01 January 1970 00:00:00 UTC. Everything else is a simple conversion, and adding/subtracting become very easy!
Assuming a 32-bit OS/Browser, could a Date object created in JavaScript rollover to 1970 if I set a date beyond 2038?
The Mozilla documentation says a year can be set to 9999, however I don't know if this is consistent across all JavaScript implementations, or if this is an accurate description of what the specification dictates.
I would think given the wording in the documentation, it seems like it's either using a 64-bit number for storing the time or storing the actual data in ISO date format.
Does anyone know how browsers implement this?
It shouldn't be - according to the ECMAScript specification seciont 15.9.1.1:
Time is measured in ECMAScript in milliseconds since 01 January, 1970 UTC. Leap seconds are ignored. It is assumed that there are exactly 86,400,000 milliseconds per day. ECMAScript number values can represent all integers from –9,007,199,254,740,991 to 9,007,199,254,740,991; this range suffices to measure times to millisecond precision for any instant that is within approximately 285,616 years, either forward or backward, from 01 January, 1970 UTC.
The actual range of times supported by ECMAScript Date objects is slightly smaller: exactly –100,000,000 days to 100,000,000 days measured relative to midnight at the beginning of 01 January, 1970 UTC.
This gives a range of 8,640,000,000,000,000 milliseconds to either side of 01 January,
1970 UTC. The exact moment of midnight at the beginning of 01 January, 1970 UTC is represented by the value +0.
Only bitwise operators in JS are 32bit. There is no version that changes this, and there is no difference if your OS is 64bit. So if someone is using bitwise on timestamps, this could happen. For example, here I use bitwise or because I want the side-effect of all bitwise operators that they convert to int, just so I loose the milliseconds of the date.
new Date('2038-01-01T01:01:01.345') / 1000 | 0; // 2145913261.
new Date('2039-01-01T01:01:01.345') / 1000 | 0; // -2117518035. Wraps around...
I could be using anything else, such as Math.round, or parseInt and there will be no problem, but if I use bitwise, it's going to wrap around.
I am unable to understand the difference between the toString() and toLocaleString() methods of a Date object in JavaScript. One thing I know is that toString() will automatically be called whenever the Date objects needs to be converted to string.
The following code returns identical results always:
var d = new Date();
document.write( d + "<br />" );
document.write( d.toString() + "<br />" );
document.write( d.toLocaleString() );
And the output is:
Tue Aug 14 2012 08:08:54 GMT+0500 (PKT)
Tue Aug 14 2012 08:08:54 GMT+0500 (PKT)
Tue Aug 14 2012 08:08:54 GMT+0500 (PKT)
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/toLocaleString
Basically, it formats the Date to how it would be formatted on the computer where the function is called, e.g. Month before Day in US, Day before Month in most of the rest of the world.
EDIT:
Because some others pointed out that the above reference isn't necessary reliable, how's this from the ECMAScript spec:
15.9.5.2 Date.prototype.toString ( )
This function returns a String value. The contents of the String are implementation->> dependent, but are intended to represent the Date in the current time zone in a convenient, human-readable form.
15.9.5.5 Date.prototype.toLocaleString ( )
This function returns a String value. The contents of the String are implementation->>dependent, but are intended to represent the Date in the current time zone in a convenient, human-readable form that corresponds to the conventions of the host environment‘s current locale.
Since you can hopefully assume that most implementations will reflect the specification, the difference is that toString() is just required to be readable, toLocaleString() should be readable in a format that the should match the users expectations based on their locale.
Converts a date to a string, using the operating system's locale's
conventions.
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/toLocaleString
toLocaleString behaves similarly to toString when converting a year
that the operating system does not properly format.
I am just checked in console of the Chrome for date and found the difference in the presentation format. Hope this could help.
var d = new Date();
console.log(d.toLocaleString()); //"04.09.2016, 15:42:44"
console.log(d.toString()); //"Sun Sep 04 2016 15:42:44 GMT+0300 (FLE Daylight Time)"
Lots of references, but none are authoritative. Note that Mozilla's documentation is for JavaScript, which is their version of ECMAScript for browsers. Other browsers use other implementations and therefore, while the MDN documentation is useful, it is not authoritative (it is also a community wiki, so not even official Mozilla documentation) and does not necessarily apply to other browsers.
The definitive reference is the ECMAScript Language specification, where the behaviour of both Date.prototype.toString and Date.prototype.toLocaleString are explained in browser independent terms.
Notable is the for both methods, the string is implementation dependent, which means that different browsers will return different strings.
Just to add. Apart from Date, it also converts/formats the normal variable.
Both functions used to format/convert the passed parameter to string but how parameter is formatted is the point to look on.
toLocalestring() used to return the formatted string based on which geography the function is called.
For the sake of simplicity.
Take this example.
It shows how toString() won't format the variable but toLocaleSting() will format it based on locale setting of the geography.
let number = 1100;
console.log(number.toString()); // "1100"
console.log(number.toLocaleString()) // 1,100
let number = 1100;
console.log(number.toString());
console.log(number.toLocaleString());
It is a great help for programmer in order to avoid to write extra function to format the string or Date. toLocaleString() will take care of this.
Hope you would find it somewhat helpful & interesting.