Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to extend the Javascript Date object?

Tags:

I'm trying to subclass/extend the native Date object, without modifying the native object itself.

I've tried this:

    var util = require('util');      function MyDate() {         Date.call(this);     }     util.inherits(MyDate, Date);      MyDate.prototype.doSomething = function() {         console.log('Doing something...');     };              var date = new MyDate();     date.doSomething();      console.log(date);     console.log(date.getHours()); 

and this:

function MyDate() {      }      MyDate.prototype = new Date();      MyDate.prototype.doSomething = function() {         console.log("DO");     }      var date = new MyDate();     date.doSomething();     console.log(date); 

In both cases, the date.doSomething() works, but when I call any of the native methods such as date.getHours() or even console.log(date), I get 'TypeError: this is not a Date object.'

Any ideas? Or am I stuck to extending the top-level Date object?

like image 330
evilcelery Avatar asked May 20 '11 16:05

evilcelery


People also ask

What is new Date () in JavaScript?

It is used to work with dates and times. The Date object is created by using new keyword, i.e. new Date(). The Date object can be used date and time in terms of millisecond precision within 100 million days before or after 1/1/1970.

What does new Date () return?

"The expression new Date() returns the current time in internal format, as an object containing the number of milliseconds elapsed since the start of 1970 in UTC.

What is the format of new Date ()?

The most used method to get the date in JavaScript is the new Date() object. By default, when you run new Date() in your terminal, it uses your browser's time zone and displays the date as a full text string, like Fri Jul 02 2021 12:44:45 GMT+0100 (British Summer Time).


2 Answers

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.

like image 184
Geoff Chappell Avatar answered Sep 25 '22 16:09

Geoff Chappell


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.

like image 29
sstur Avatar answered Sep 24 '22 16:09

sstur