Reputation: 1032
I'm trying to figure out if there is a way to have an object property defined in its prototype as a dynamic value that can change every time an instance of the object is created. That's kind of the best way I can describe it; I have made a fiddle to show what I'm trying to do (though it doesn't work).
var Response = {
LCID: 321
};
Date.prototype.LCID = Number(0);
Date.prototype.LCID.valueOf = function() { return Response.LCID; };
document.write((new Date()).LCID);
Response.LCID = 456;
document.write((new Date()).LCID);
What I'm trying to achieve is that Response.LCID
can change over the lifetime of the code as you can see from me changing its value in the code later on. Whenever I create a Date
object, I want the value of (new Date()).LCID
to be the current value of Response.LCID
, not just the value that it had when I first create Date.prototype.LCID
.
Is there any way this can be done? The biggest limitation is that it has to work in JavaScript 1.5... though I would be curious to see if it could be done in recent versions.
Upvotes: 1
Views: 1081
Reputation: 10874
Ok this does it using the __defineGetter__
method, however I am not sure how it will behave on all browser but that the only way I could find to achieve what you want (well I think this time it is what you want)
http://jsfiddle.net/tx2fW/6/ working example.
var Response = {
LCID: 321
};
var d = Date.prototype;
d._LCID = Number(0);
d.getLCID = function() {
if (d._LCID != Response.LCID) d._LCID = Response.LCID;
return d._LCID ;
};
d.__defineGetter__("LCID", function() {
return this.getLCID();
});
document.write((new Date()).LCID);
Response.LCID = 456;
document.write((new Date()).LCID);
For alternative to __defineGetter__
please see this post
Upvotes: 1
Reputation: 1032
After some more research and experimenting, I was able to actually solve the issue. I had tried playing with the Date constructor and such, but I didn't have much luck in my initial trials - apparently because I overlooked the fact that the Date object is unique in that it differs in functionality depending on how it is called (as a function or object constructor). This means that you can't just do Date.prototype.constructor.apply(this, arguments)
since all you'll ever get back is a string (the Date object is being called as a function).
After having found this thread and reading it, I came up with the following code that creates an actual Date object (or string if called as a function) and mimics the built-in Date object perfectly (as far as my tests show anyways). Every time a new Date object is created, it gets the LCID property which is dynamically generated during object creation which is exactly what I needed.
Date = (function(orig) {
var date = function(a, b, c, d, e, f, g) {
var object = (this instanceof Object ? (arguments.length < 1 ? new orig() : (arguments.length < 2 ? new orig(a) : (arguments.length < 4 ? new orig(a, b || 0, c || 1) : new orig(a, b, c, d || 0, e || 0, f || 0, g || 0)))) : orig());
object.LCID = Response.LCID;
return object;
};
date.prototype = orig.prototype;
return date;
})(Date);
I also created a bunch of test cases to ensure that there is no difference from a built-in Date object, or using this code (comment out this code to see the results using the built-in Date object and compare).
var Response = { 'LCID': 123 };
Date = (function(orig) {
var date = function(a, b, c, d, e, f, g) {
var object = (this instanceof Object ? (arguments.length < 1 ? new orig() : (arguments.length < 2 ? new orig(a) : (arguments.length < 4 ? new orig(a, b || 0, c || 1) : new orig(a, b, c, d || 0, e || 0, f || 0, g || 0)))) : orig());
object.LCID = Response.LCID;
return object;
};
date.prototype = orig.prototype;
return date;
})(Date);
var x = new Date();
document.writeln(x);
document.writeln(x.LCID);
document.writeln(x.getFullYear());
document.writeln(typeof x);
document.writeln(Object.prototype.toString.call(x));
document.writeln(x instanceof Date);
document.writeln("<br/>");
Response.LCID = 456;
var y = new Date();
document.writeln(y);
document.writeln(y.LCID);
document.writeln(y.getFullYear());
document.writeln(typeof y);
document.writeln(Object.prototype.toString.call(y));
document.writeln(y instanceof Date);
document.writeln("<br/>");
document.writeln(Date());
document.writeln(new Date());
document.writeln(new Date(2012));
document.writeln(new Date(2012, 7));
document.writeln(new Date(2012, 7, 14));
document.writeln(new Date(2012, 7, 14, 9));
document.writeln(new Date(2012, 7, 14, 9, 45));
document.writeln(new Date(2012, 7, 14, 9, 45, 27));
document.writeln(new Date(2012, 7, 14, 9, 45, 27, 687));
This is also available as an updated fiddle: http://jsfiddle.net/tx2fW/9/
Upvotes: 0
Reputation: 349012
Number(0) === 0
. Modifying .valueOf
and .toString
on primitive values have no effect.
The correct way to do this is to pass an instance of the Number
constructor, using the new
operator:
var Response = {
LCID: 321
};
Date.prototype.LCID = new Number(); // <-- Use the "new" operator
Date.prototype.LCID.valueOf = function() { return Response.LCID; };
LCID
is an object. typeof new Date().LCID === 'object'
.LCID
is a true instance of Number
. new Date().LCID instanceof Number === true
LCID
is equal to 321: (new Date().LCID == 321) === true
LCID
is not identical to 321: (new Date().LCID === 321) === false
.PS. If you're not familiar with ==
versus ===
, see Which equals operator (== vs ===) should be used in JavaScript comparisons?
Upvotes: 1