Let me start with a specific example of what I'm trying to do.
I have an array of year, month, day, hour, minute, second and millisecond components in the form [ 2008, 10, 8, 00, 16, 34, 254 ]
. I'd like to instantiate a Date object using the following standard constructor:
new Date(year, month, date [, hour, minute, second, millisecond ])
How can I pass my array to this constructor to get a new Date instance? [ Update: My question actually extends beyond this specific example. I'd like a general solution for built-in JavaScript classes like Date, Array, RegExp, etc. whose constructors are beyond my reach. ]
I'm trying to do something like the following:
var comps = [ 2008, 10, 8, 00, 16, 34, 254 ];
var d = Date.prototype.constructor.apply(this, comps);
I probably need a "new
" in there somewhere. The above just returns the current time as if I had called "(new Date()).toString()
". I also acknowledge that I may be completely in the wrong direction with the above :)
Note: No eval()
and no accessing the array items one by one, please. I'm pretty sure I should be able to use the array as is.
Update: Further Experiments
Since no one has been able to come up with a working answer yet, I've done more playing around. Here's a new discovery.
I can do this with my own class:
function Foo(a, b) {
this.a = a;
this.b = b;
this.toString = function () {
return this.a + this.b;
};
}
var foo = new Foo(1, 2);
Foo.prototype.constructor.apply(foo, [4, 8]);
document.write(foo); // Returns 12 -- yay!
But it doesn't work with the intrinsic Date class:
var d = new Date();
Date.prototype.constructor.call(d, 1000);
document.write(d); // Still returns current time :(
Neither does it work with Number:
var n = new Number(42);
Number.prototype.constructor.call(n, 666);
document.write(n); // Returns 42
Maybe this just isn't possible with intrinsic objects? I'm testing with Firefox BTW.
I've done more investigation of my own and came up with the conclusion that this is an impossible feat, due to how the Date class is implemented.
I've inspected the SpiderMonkey source code to see how Date was implemented. I think it all boils down to the following few lines:
When Date is used as a function (either as
Date()
orDate.prototype.constructor()
, which are exactly the same thing), it defaults to returning the current time as a string in the locale format. This is regardless of any arguments that are passed in:I don't think there's anything that can be done at the JS level to circumvent this. And this is probably the end of my pursuit in this topic.
I've also noticed something interesting:
Date.prototype
is a Date instance with the internal value ofNaN
and therefore,IE doesn't disappoint us. It does things a bit differently and probably sets the internal value to
-1
so that Date.prototype always returns a date slightly before epoch.Update
I've finally dug into ECMA-262 itself and it turns out, what I'm trying to achieve (with the Date object) is -- by definition -- not possible:
It's less than elegant, but here's a solution:
The way this works should be pretty obvious. It creates a function through code generation. This example has a fixed number of parameters for each constructor you create, but that's useful anyway. Most of the time you have atleast a maximum number of arguments in mind. This also is better than some of the other examples here because it allows you to generate the code once and then re-use it. The code that's generated takes advantage of the variable-argument feature of javascript, this way you can avoid having to name each parameter (or spell them out in a list and pass the arguments in to the function you generate). Here's a working example:
This will return the following:
It is indeed still...a bit ugly. But it atleast conveniently hides the mess and doesn't assume that compiled code itself can get garbage collected (since that may depend on the implementation and is a likely area for bugs).
Cheers, Scott S. McCoy
You can do it with flagrant, flagrant abuse of eval:
sample usage:
enjoy =).
It will work with ES6 spread operator. You simply:
Here is another solution: