Instantiating a ClassThe new operator requires a single, postfix argument: a call to a constructor. The name of the constructor provides the name of the class to instantiate. The constructor initializes the new object. The new operator returns a reference to the object it created.
constructor. The constructor property returns a reference to the Object constructor function that created the instance object. Note that the value of this property is a reference to the function itself, not a string containing the function's name.
An instantiation pattern in JavaScript is a way to create an object using functions. There are five instantiation patterns: Functional, Functional-shared, Prototypical, Pseudoclassical, and ES6.
Using a constructor In JavaScript, all functions have a property named prototype . When you call a function as a constructor, this property is set as the prototype of the newly constructed object (by convention, in the property named __proto__ ). Here we create: an object personPrototype , which has a greet() method.
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:
static JSBool
Date(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
jsdouble *date;
JSString *str;
jsdouble d;
/* Date called as function. */
if (!(cx->fp->flags & JSFRAME_CONSTRUCTING)) {
int64 us, ms, us2ms;
jsdouble msec_time;
/* NSPR 2.0 docs say 'We do not support PRMJ_NowMS and PRMJ_NowS',
* so compute ms from PRMJ_Now.
*/
us = PRMJ_Now();
JSLL_UI2L(us2ms, PRMJ_USEC_PER_MSEC);
JSLL_DIV(ms, us, us2ms);
JSLL_L2D(msec_time, ms);
return date_format(cx, msec_time, FORMATSPEC_FULL, rval);
}
/* Date called as constructor. */
// ... (from here on it checks the arg count to decide how to create the date)
When Date is used as a function (either as Date()
or Date.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:
alert(Date()); // Returns "Thu Oct 09 2008 23:15:54 ..."
alert(typeof Date()); // Returns "string"
alert(Date(42)); // Same thing, "Thu Oct 09 2008 23:15:54 ..."
alert(Date(2008, 10, 10)); // Ditto
alert(Date(null)); // Just doesn't care
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:
/* Set the value of the Date.prototype date to NaN */
proto_date = date_constructor(cx, proto);
if (!proto_date)
return NULL;
*proto_date = *cx->runtime->jsNaN;
Date.prototype
is a Date instance with the internal value of NaN
and therefore,
alert(Date.prototype); // Always returns "Invalid Date"
// on Firefox, Opera, Safari, Chrome
// but not Internet Explorer
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.
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:
15.9.2 The Date Constructor Called as a Function
When Date is called as a function rather than as a constructor, it returns a string representing the current time (UTC).
NOTE The function call
Date(…)
is not equivalent to the object creation expressionnew Date(…)
with the same arguments.15.9.2.1 Date ( [ year [, month [, date [, hours [, minutes [, seconds [, ms ] ] ] ] ] ] ] )
All of the arguments are optional; any arguments supplied are accepted but are completely ignored. A string is created and returned as if by the expression
(new Date()).toString()
.
I'd hardly call this elegant, but in my testing (FF3, Saf4, IE8) it works:
var arr = [ 2009, 6, 22, 10, 30, 9 ];
Instead of this:
var d = new Date( arr[0], arr[1], arr[2], arr[3], arr[4], arr[5] );
Try this:
var d = new Date( Date.UTC.apply( window, arr ) + ( (new Date()).getTimezoneOffset() * 60000 ) );
This is how you might solve the specific case:-
function writeLn(s)
{
//your code to write a line to stdout
WScript.Echo(s)
}
var a = [ 2008, 10, 8, 00, 16, 34, 254 ]
var d = NewDate.apply(null, a)
function NewDate(year, month, date, hour, minute, second, millisecond)
{
return new Date(year, month, date, hour, minute, second, millisecond);
}
writeLn(d)
However you are looking for a more general solution. The recommended code for creating a constructor method is to have it return this
.
Hence:-
function Target(x , y) { this.x = x, this.y = y; return this; }
could be constructed :-
var x = Target.apply({}, [1, 2]);
However not all implementations work this way not least because the prototype chain would be wrong:-
var n = {};
Target.prototype = n;
var x = Target.apply({}, [1, 2]);
var b = n.isPrototypeOf(x); // returns false
var y = new Target(3, 4);
b = n.isPrototypeOf(y); // returns true
It's less than elegant, but here's a solution:
function GeneratedConstructor (methodName, argumentCount) {
var params = []
for (var i = 0; i < argumentCount; i++) {
params.push("arguments[" + i + "]")
}
var code = "return new " + methodName + "(" + params.join(",") + ")"
var ctor = new Function(code)
this.createObject = function (params) {
return ctor.apply(this, params)
}
}
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:
var dateConstructor = new GeneratedConstructor("Date", 3)
dateConstructor.createObject( [ 1982, 03, 23 ] )
This will return the following:
Fri Apr 23 1982 00:00:00 GMT-0800 (PST)
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With