How to extend the Javascript Date object?

Check out the MDC docs on Date specifically:

Note: Note that Date objects can only be instantiated by calling Date or using it as a constructor; unlike other JavaScript object types, Date objects have no literal syntax.

It seems like the Date object isn't really a JS object at all. When I was writing an extension library, I ended up doing the following:

function MyDate() {
   var _d=new Date();
   function init(that) {
      var i;
      var which=['getDate','getDay','getFullYear','getHours',/*...*/,'toString'];
      for (i=0;i<which.length;i++) {
         that[which[i]]=_d[which[i]]; 
      }
   }
   init(this);
   this.doSomething=function() {
    console.log("DO");
   }
}

At least I did that first. The limitations of the JS Date object in the end got the better of me and I switched to my own data storage approach (eg. why does getDate=day of year?)


In ES6, it will be possible to subclass built-in constructors (Array, Date, and Error) - reference

Problem is there is no way to do this with current ES5 engines, as Babel indicates and will require a browser with native ES6 support.

The current ES6 browser support for subclassing is pretty weak / non-existant as of today (2015-04-15).


Looking at the v8 code, in date.js:

function DateGetHours() {
  var t = DATE_VALUE(this);
  if (NUMBER_IS_NAN(t)) return t;
  return HOUR_FROM_TIME(LocalTimeNoCheck(t));
}

And looks like DATE_VALUE is a macro that does this:

DATE_VALUE(arg) = (%_ClassOf(arg) === 'Date' ? %_ValueOf(arg) : ThrowDateTypeError());

So, seems like v8 won't let you subclass Date.


This can be done in ES5. It requires modifying the prototype chain directly. This is done using __proto__ or Object.setPrototypeOf(). I'm using __proto__ in the sample code since that's most widely supported (although the standard is Object.setPrototypeOf).

function XDate(a, b, c, d, e, f, g) {
  var x;
  switch (arguments.length) {
    case 0:
      x = new Date();
      break;
    case 1:
      x = new Date(a);
      break;
    case 2:
      x = new Date(a, b);
      break;
    case 3:
      x = new Date(a, b, c);
      break;
    case 4:
      x = new Date(a, b, c, d);
      break;
    case 5:
      x = new Date(a, b, c, d, e);
      break;
    case 6:
      x = new Date(a, b, c, d, e, f);
      break;
    default:
      x = new Date(a, b, c, d, e, f, g);
  }
  x.__proto__ = XDate.prototype;
  return x;
}

XDate.prototype.__proto__ = Date.prototype;

XDate.prototype.foo = function() {
  return 'bar';
};

The trick is that we actually instantiate a Date object (with the correct number of arguments) which gives us an object with it's internal [[Class]] set correctly. Then we modify it's prototype chain to make it an instance of XDate.

So, we can verify all this by doing:

var date = new XDate(2015, 5, 18)
console.log(date instanceof Date) //true
console.log(date instanceof XDate) //true
console.log(Object.prototype.toString.call(date)) //[object Date]
console.log(date.foo()) //bar
console.log('' + date) //Thu Jun 18 2015 00:00:00 GMT-0700 (PDT)

This is the only way I know of to subclass date because the Date() constructor does some magic to set the internal [[Class]] and most date methods require that to be set. This will work in Node, IE 9+ and almost all other JS engines.

Similar approach can be used for subclassing Array.