1

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);

http://jsfiddle.net/tx2fW/2/

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.

0

3 Answers 3

1

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; };

Annotated demo and notes: http://jsfiddle.net/tx2fW/7/

  • 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.
    (because LCID is an object, and 321 is a primitive number value).

PS. If you're not familiar with == versus ===, see Which equals operator (== vs ===) should be used in JavaScript comparisons?

Sign up to request clarification or add additional context in comments.

5 Comments

+1 for getting the answer right and posting the code here. But no one should mess with built–in prototypes. Seems you got a drive–by -1.
@RobG About modifying prototypes: He did not elaborate his application, so I cannot judge whether his decision is OK or not. Rule of thumb: Does the added property directly relate to the Date constructor? If not: Do not extend the prototype.
Thank you for this - I had actually tried that before and kept trying other ways because your code fails if JavaScript doesn't have to cast/coerce the LCID property in to another type. Your code only works because it's being converted to a string for concatenation. Try outputting just (new Date()).LCID to see what happens (you get a zero).
@EliSand I explained that in my annotations: It is an object. One character can make the method to behave as expected, across all (ancient) browsers: +(new Date).LCID (notice the unary +), see also point s and t of Comparison between all number-conversion methods.
Oh, and fully aware of == and ===, as well as when and why to extend an objects prototype. This properly does directly relate to the object; I'm creating a locale ID for Date objects. This is for server-side JavaScript in Classic ASP (Response.LCID is an ASP object).
1

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

6 Comments

No, I specifically want Response.LCID to change and have it's change reflected in new Date objects. I do not want to have to change Date.prototype.LCID.
Need your own wrapper for Date then, otherwise what you ask can't be done jsfiddle.net/tx2fW/4
Using a custom date object is also not an option unfortunately. What I'm trying to ultimately achieve is being able to attach locale ID's to objects, either built-in objects or custom objects. If I can't do it for built-in objects, the point is lost since I would have to get other programmers to be aware of all the custom objects to use instead of built-ins.
Yeah I see what you are trying to achieve. The only way that could be done is by modifying the Date object constructor I guess but I don't think you can do that in JS (need to play with it and see). As that way it would set its own value on creation.
Internet Explorer JScript doesn't support __defineGetter__.
|
0

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/

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.