bendun.cc

String(new Date(NaN))

Written , a 2 minute read

I'm glad that I didn't ever care too much for ECMAScript 5 or Internet Explorer. I started with web development around 2015 and most tech that classmates used around me felt clunky and unnecessary for me. I was having way too much with ECMAScript 6 features, CSS3 and HTML5.

This fresh look (and not working with enterprise JavaScript for next 4 years) meant that I missed all that noise of jQuery, Bootstrap and pollyfills. The only thing that seemed interesting to me at the time was CoffeeScript since I didn't know Python back then and this kind of syntax felt fresh and interesting.

While reading "The State of ES5 on the Web by Philip Walton, I realized how lucky I was to skip all of that. Especially when I noticed how weird some of the pollyfills were.

String(new Date(NaN)) behaviour was left to implementation, as stated in ECMAScript 5 specification:

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.

ECMAScript 6 defined the output, by delegation to the ToDateString(tv) abstract operation:

21.4.4.41.4 ToDateString ( tv )

The abstract operation ToDateString takes argument tv (an integral Number or NaN) and returns a String. It performs the following steps when called:

  1. If tv is NaN, return "Invalid Date".
  2. Let t be LocalTime(tv).
  3. Return the string-concatenation of DateString(t), the code unit 0x0020 (SPACE), TimeString(t), and TimeZoneString(tv).

The first step of this algorithm lead to this lovely pollyfill inside core-js (simplified by me):

if (String(new Date(NaN)) !== 'Invalid Date') {
  var toString = Date.prototype.toString;
  Date.prototype.toString = function() {
    var value = this.getTime();
    return value === value ? toString.call(this) : 'Invalid Date';
  });
}

Which utilizes IEEE-754 lack of equality between NaNs (shouldn't this return undefined instead of false since this comparison is unordered?) to test for their presence (with value === value), which is recommended in ECMAScript 5 standard:

15.1.2.4 isNaN (number)

Returns true if the argument coerces to NaN, and otherwise returns false.

NOTE

A reliable way for ECMAScript code to test if a value X is a NaN is an expression of the form X !== X. The result will be true if and only if X is a NaN.

Why isNaN wasn't implemented as reliable way to detect NaNs is beyond me (current standard recommends the same by the way).