I\'m trying to subclass/extend the native Date object, without modifying the native object itself.
I\'ve tried this:
var util = require(\'util\')
You can also use github.com/loganfsmyth/babel-plugin-transform-builtin-extend
Example:
import 'babel-polyfill'
export default class MyDate extends Date {
constructor () {
super(...arguments)
}
}
Based on the answers by @sstur and its improvement by @bucabay:
Note that __proto__
is being used in those answers, which is deprecated and its use is strongly discouraged, at least according to the MDN docs.
Fortunately, it is possible to do what is desired without using __proto__
by setting each individual function from Date.prototype
in our class, which is simplified by making use of Object.getOwnPropertyNames().
function XDate() {
var x = new (Function.prototype.bind.apply(Date, [Date].concat(Array.prototype.slice.call(arguments))));
Object.getOwnPropertyNames(Date.prototype).forEach(function(func) {
this[func] = function() {
return x[func].apply(x, Array.prototype.slice.call(arguments));
};
}.bind(this));
this.foo = function() {
return 'bar';
};
}
A minor disadvantage of this method is that XDate
isn't actually a subclass of Date
. The check xdateobj instanceof Date
is false
. But this shouldn't be a worry as you can anyway use the methods of the Date class.
I know this is a bit late, but for others who may encounter this issue, I manged to effectively subclass Date for a polyfill I needed for PhantomJS. The technique seems to work in other browser as well. There were a few additional issues to work out but essentially I followed the same approach as Rudu.
The full commented code is at https://github.com/kbaltrinic/PhantomJS-DatePolyfill.
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).
var SubDate = function() {
var dateInst = new Date(...arguments); // spread arguments object
/* Object.getPrototypeOf(dateInst) === Date.prototype */
Object.setPrototypeOf(dateInst, SubDate.prototype); // redirectionA
return dateInst; // now instanceof SubDate
};
Object.setPrototypeOf(SubDate.prototype, Date.prototype); // redirectionB
// do something useful
Object.defineProperty(SubDate.prototype, 'year', {
get: function() {return this.getFullYear();},
set: function(y) {this.setFullYear(y);}
});
var subDate = new SubDate();
subDate.year; // now
subDate.year = 2050; subDate.getFullYear(); // 2050
The problem with the Date
constructor function is already explained in the other answers. You can read about the Date.call(this, ...arguments)
problem on Date | MDN (first Note).
This solution is a compact workaround which works as intended in all supporting browsers.
I believe Date is actually a static function, not a true object, and as such cannot be inherited from using prototypes, so you'll need to create a façade class to wrap any Date functionality you need.
I'd try constructing your new date object as:
function MyDate(value) {
this.value=new Date(value);
// add operations that operate on this.value
this.prototype.addDays=function(num){
...
};
this.prototype.toString=function() {
return value.toString();
};
}
// add static methods from Date
MyDate.now=Date.now;
MyDate.getTime=Date.getTime;
...
(I'm not near a system I can test this on, but I hope you get the idea.)