Topic: Instantiating a JavaScript object by calling prototype.constructor.apply |
|
---|---|
Author | Thread |
Nervous Wreck (II) Inmate From: Toronto |
posted 10-08-2008 21:20
Fellow inmates, code: new Date(year, month, date [, hour, minute, second, millisecond ])
code: var comps = [ 2008, 10, 8, 00, 16, 34, 254 ]; var d = Date.prototype.constructor.apply(this, comps);
|
Nervous Wreck (II) Inmate From: Toronto |
posted 10-09-2008 05:11
I've done a few more experiments: code: 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!
code: var d = new Date(); Date.prototype.constructor.call(d, 1000); document.write(d); // Still returns current time :(
code: var n = new Number(42); Number.prototype.constructor.call(n, 666); document.write(n); // Returns 42
|
Bipolar (III) Inmate From: |
posted 10-09-2008 06:05
Very interesting topic. I've been struggling to wrap my head around JS OOP for some time now - It seems pretty wonky compared to other high level languages. Anyway, I've been searching google and experimenting for about the last hour trying to find something. The best I could come up with is that I think prototype.constructor is not the right thing. There is a method called constructor that does return some weird garbage that appears to be related to initialization, however I don't believe that it is the actual constructor. I think it's too late after you've called new ObjectName() because the constructor has already been invoked: you can't change it now. code: // The problem here is that constructor seems to not be the correct method // to override the actual class constructor - so what is the right way? Date.prototype.constructor = function(myargs) { // This calls the original constructor with myargs as an array, just like you requested Date.apply(this, myargs); } var comps = [ 2008, 10, 8, 00, 16, 34, 254 ]; // NOW we try to instantiate a Date object after we've altered the behavior through the prototype... var d = new Date(comps); var year = d.getYear(); var month = d.getMonth(); var day = d.getDate();
|
Paranoid (IV) Inmate From: Norway |
posted 10-09-2008 09:23
I gave it a shot yesterday evening, in Opera 9.6 and FireFox 3.0.3 and came to the same conclusion as MaGnA. |
Nervous Wreck (II) Inmate From: Toronto |
posted 10-10-2008 05:10
Thanks esskay, poi for looking into this. code: 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)
code: /* 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;
code: alert(Date.prototype); // Always returns "Invalid Date" on FF, Opera, Safari, Chrome but not IE
|
Paranoid (IV) Inmate From: Umeå, Sweden |
posted 10-10-2008 05:42
The built-in objects are different from native functions because they do not necessarily run the same code when called as constructors as they do when called as functions. Native functions (i.e. ECMAScript author declared functions) on the other hand always run the same code during function calls as during constructor calls. |
Nervous Wreck (II) Inmate From: Toronto |
posted 10-10-2008 06:13
liorean: Thanks for beautifully summing it all up in just a few paragraphs! code: Object(42).toSource() -> (new Number(42)) Object("hi").toSource() -> (new String("hi")) Object(false).toSource() -> (new Boolean(false))
|