Subclassing Date weirdness.

Discussion in 'Javascript' started by nick, Apr 18, 2010.

  1. nick

    nick Guest

    I decided to I wanted to subclass the native Date object, but realized
    that you can't call Date.prototype's function properties with anything
    but a 'pure' date object as the execution context. So, I decided to
    wrap all of Date.prototype's important functions, which worked out
    pretty well...

    The weirdness comes into play with the toString and valueOf methods.
    In particular, my MyDate class gives different values for (''+new
    MyDate) and (new MyDate.toString()), which confuses me. I didn't
    expect the results to differ from (''+new Date) and (new
    Date.toString()).

    Here's some example code to reproduce it...

    /** datetest.js */

    // MyDate constructor
    var MyDate = function () {
    this._date = new Date();
    }

    // MyDate class definition
    MyDate.prototype = (function(){

    // for instanceof
    var Clone = new Function;
    Clone.prototype = Date.prototype;
    var base = new Clone;

    // native methods of Date.prototype
    var _nm = ['getDate','getDay','getFullYear','getHours',
    'getMilliseconds','getMinutes','getMonth','getSeconds',
    'getTime','getTimezoneOffset','getUTCDate','getUTCDay',
    'getUTCFullYear','getUTCHours','getUTCMilliseconds',
    'getUTCMinutes','getUTCMonth','getUTCSeconds','getYear',
    'setDate','setFullYear','setHours','setMilliseconds',
    'setMinutes','setMonth','setSeconds','setTime',
    'setUTCDate','setUTCFullYear','setUTCHours',
    'setUTCMilliseconds','setUTCMinutes','setUTCMonth',
    'setUTCSeconds','setYear','toDateString','toGMTString',
    'toISOString','toJSON','toLocaleDateString',
    'toLocaleString','toLocaleTimeString','toString',
    'toTimeString','toUTCString','valueOf'];

    // create wrappers for native methods
    for (var i=_nm.length; i--;) (function (f) {
    base[f] = function() {
    return Date.prototype[f].apply(this._date, arguments);
    }
    })(_nm);

    // our class prototype
    return base;

    })();

    // testing it out

    var c = console;

    c.log("======== Date ========");
    c.log("new Date() : ", new Date());
    c.log("''+new Date() : ", ''+new Date());
    c.log("(new Date()).toString() : ", (new Date()).toString());
    c.log("(new Date()).valueOf() : ", (new Date()).valueOf());

    c.log("======== MyDate ========");
    c.log("new MyDate() : ", new MyDate());
    c.log("''+new MyDate() : ", ''+new MyDate());
    c.log("(new MyDate()).toString() : ", (new MyDate()).toString());
    c.log("(new MyDate()).valueOf() : ", (new MyDate()).valueOf());

    /// EOF

    Anyone have any idea what's going on here?

    -- Nick
    nick, Apr 18, 2010
    #1
    1. Advertising

  2. nick wrote:

    > I decided to I wanted to subclass the native Date object, but realized
    > that you can't call Date.prototype's function properties with anything
    > but a 'pure' date object as the execution context. So, I decided to
    > wrap all of Date.prototype's important functions, which worked out
    > pretty well...


    That design is not really good decision. It is memory inefficient and
    break forward compatible with non generics methods for Date
    instances.

    > The weirdness comes into play with the toString and valueOf methods.
    > In particular, my MyDate class gives different values for (''+new
    > MyDate) and (new MyDate.toString()), which confuses me. I didn't
    > expect the results to differ from  (''+new Date) and (new
    > Date.toString()).


    By specification that is normal behavior, because Date instances have
    special [[DefaultValue]]. During evaluation of addition expression,
    objects will be converted to primitive value. For type converting will
    be use internal [[DefaultValue]] of that object, without passing hint
    argument.

    | ECMA-262-3
    | 8.6.2.6 [[DefaultValue]] (hint)
    | When the [[DefaultValue]] method of O is called with no hint,
    | then it behaves as if the hint were Number, unless O is
    | a Date object (section 15.9), in which case
    | it behaves as if the hint were String.

    From that quotation when you create instance object:

    var obj = new MyDate();

    For object referred by `obj' if call [[DefaultValue]] method with no
    hint, will be treat as hint is Number.
    Asen Bozhilov, Apr 18, 2010
    #2
    1. Advertising

  3. In comp.lang.javascript message <daa5afc9-f5d5-47ab-a4b2-3d68139f1029@8g
    2000yqz.googlegroups.com>, Sun, 18 Apr 2010 12:52:49, nick
    <> posted:

    >I decided to I wanted to subclass the native Date object, but realized
    >that you can't call Date.prototype's function properties with anything
    >but a 'pure' date object as the execution context. So, I decided to
    >wrap all of Date.prototype's important functions, which worked out
    >pretty well...


    You might like to look at :
    <URL:http://www.merlyn.demon.co.uk/js-dobj2.htm> Alt. date object
    <URL:http://www.merlyn.demon.co.uk/js-datex.htm> Date errors
    <URL:http://www.merlyn.demon.co.uk/js-dates.htm> Date index, ff.

    Note that, when reporting unexpected results, it is well to indicate
    which version of which browser (or other host) is in use, ditto for
    operating system, and the location to which your system is set.

    --
    (c) John Stockton, nr London, UK. ?@merlyn.demon.co.uk Turnpike v6.05.
    Web <URL:http://www.merlyn.demon.co.uk/> - w. FAQish topics, links, acronyms
    PAS EXE etc : <URL:http://www.merlyn.demon.co.uk/programs/> - see 00index.htm
    Dates - miscdate.htm estrdate.htm js-dates.htm pas-time.htm critdate.htm etc.
    Dr J R Stockton, Apr 19, 2010
    #3
  4. nick

    nick Guest

    On Apr 19, 12:26 pm, Dr J R Stockton <>
    wrote:
    >
    > You might like to look at :
    >   <URL:http://www.merlyn.demon.co.uk/js-dobj2.htm>   Alt. date object
    >   <URL:http://www.merlyn.demon.co.uk/js-datex.htm>   Date errors
    >   <URL:http://www.merlyn.demon.co.uk/js-dates.htm>   Date index, ff.


    Nice... the thing I'm working on is a port of PHP's date() formatting;
    looks like you've done something pretty similar. I'll post what I've
    got in pastebin or something when I get home so you can have a look,
    it might be interesting to you.

    > Note that, when reporting unexpected results, it is well to indicate
    > which version of which browser (or other host) is in use, ditto for
    > operating system, and the location to which your system is set.


    Good point. I believe I tested it in latest versions of GC and FF, but
    I was on my way out the door when I got to that point so I may be
    mistaken. The behavior I was noticing was basically:

    (''+new Date) == (new Date).toString()
    (''+new Date) != (new Date).valueOf()

    (''+new MyDate) != (new MyDate).toString()
    (''+new MyDate) == (new MyDate).valueOf()

    This isn't what I expected (I expected ''+anything to be the same as
    anything.toString() pretty much across the board), but it's probably a
    result of my not having taken the time to fully understand the inner
    workings of toString and valueOf.

    I'll try to post something as little more coherent (and respond to
    Asen, sorry Asen) when I get back to the house ;)

    -- Nick
    nick, Apr 19, 2010
    #4
  5. nick

    nick Guest

    On Apr 18, 5:30 pm, Asen Bozhilov <> wrote:
    ....
    > That design is not really good decision. It is memory inefficient and
    > break forward compatible with non generics methods for Date
    > instances.


    True, but can you think of a more efficient way to to extend Date? Or
    do you think I should scrap the idea of extending Date altogether and
    instead make other classes / functions that act on instances of Date?

    > By specification that is normal behavior, because Date instances have
    > special [[DefaultValue]]. During evaluation of addition expression,
    > objects will be converted to primitive value. For type converting will
    > be use internal [[DefaultValue]] of that object, without passing hint
    > argument.


    Thanks for the explanation. Apparently only pure Date instances get
    this special behavior, just being an 'instanceof Date' isn't good
    enough.

    I guess DefaultValue and hint are internal stuff I have no control
    over?

    [snip]

    > For object referred by `obj' if call [[DefaultValue]] method with no
    > hint, will be treat as hint is Number.


    How can I call it with a hint... by doing something like
    Number(myDate) or String(myDate)?

    -- Nick
    nick, Apr 20, 2010
    #5
  6. nick

    nick Guest

    On Apr 20, 12:19 am, Johannes Baagoe <> wrote:
    [...]
    > When I had a similar project some time ago, what I finally decided (with
    > some help from this newsgroup) was not to subclass, but to combine. That
    > is, I made a conctructor that  returned not an augmented Date object, but
    > an Object containing a Date object used internally by the various methods..
    >
    > The result is here:http://baagoe.com/en/ES/XsDateTime.js


    We're doing a very similar thing, wrapping all the generic
    functions :)

    You wrote:

    for (var i = 0; i < methods.length; i++) {
    (function(method){
    XsDateTime.prototype[method] = function() {
    return Date.prototype[method].apply(this.date, arguments);
    };
    })(methods);
    }

    I wrote:

    for (var i=_nm.length; i--;) (function (f) {
    base[f] = function() {
    return Date.prototype[f].apply(this._date, arguments);
    }
    })(_nm);


    > Feel free to criticise, copy and use.


    You stole my idea! Just kidding. But hey, I worked out the weirdness
    with toString vs. valueOf... going to post about it in response to my
    first post so it doesn't get lost.

    -- Nick
    nick, Apr 20, 2010
    #6
  7. nick

    nick Guest

    I think I worked out. In the class prototype definition:

    base.valueOf = function(){
    return new Number(this._date.valueOf())
    }

    Looks like because valueOf returns an object and not a primitive,
    toString gets used instead with the plus operator (just like Date
    instances). MyDates seems to act just like Dates now (but they're
    extendable).

    -- Nick
    nick, Apr 20, 2010
    #7
  8. nick wrote:
    > Asen Bozhilov wrote:


    > > By specification that is normal behavior, because Date instances have
    > > special [[DefaultValue]]. During evaluation of addition expression,
    > > objects will be converted to primitive value. For type converting will
    > > be use internal [[DefaultValue]] of that object, without passing hint
    > > argument.

    >
    > Thanks for the explanation. Apparently only pure Date instances get
    > this special behavior, just being an 'instanceof Date' isn't good
    > enough.
    > I guess DefaultValue and hint are internal stuff I have no control
    > over?


    Internal methods are not inherited via prototype chain. For example
    Function instance has internal [[Call]] and [[Construct]] which are
    used during evaluation of `CallExpression` and `NewExpression`. If I
    inherit from Function object, created object after that does not have
    these internal methods because they are not inherited via prototype
    chain. For example of my words:

    function ExtendFunction() {}
    ExtendFunction.prototype = function(){};

    var f = new ExtendFunction();

    print(f instanceof Function); //true

    /* If object has [[Call]] method typeof
    * must return primitive string value "function"
    */
    print(typeof f == 'function'); //false

    try {
    f(); //Invoke internal [[Call]]
    }catch (e) {
    print(e instanceof TypeError); //true
    }

    try {
    new f(); //Invoke internal [[Construct]]
    }catch (e) {
    print(e instanceof TypeError); //true
    }

    > > For object referred by `obj' if call [[DefaultValue]] method with no
    > > hint, will be treat as hint is Number.

    >
    > How can I call it with a hint... by doing something like
    > Number(myDate) or String(myDate)?


    The question is to which value you want to convert that object? When
    you answer on that question you can find way to do that conversion.
    See:
    <URL: http://www.jibbering.com/faq/faq_notes/type_convert.html /> By
    Richard Cornford.
    Asen Bozhilov, Apr 22, 2010
    #8
  9. nick

    nick Guest

    On Apr 22, 4:40 pm, Asen Bozhilov <> wrote:
    > nick wrote:
    > > I guess DefaultValue and hint are internal stuff I have no control
    > > over?


    > Internal methods are not inherited via prototype chain. [...]


    I see what you mean. I have actually tested something very similar to
    the example you gave, so it makes perfect sense to me. Thanks for
    helping explain it.

    > > > For object referred by `obj' if call [[DefaultValue]] method with no
    > > > hint, will be treat as hint is Number.


    > > How can I call it with a hint... by doing something like
    > > Number(myDate) or String(myDate)?


    > The question is to which value you want to convert that object? When
    > you answer on that question you can find way to do that conversion.
    > See:
    > <URL:http://www.jibbering.com/faq/faq_notes/type_convert.html/> By
    > Richard Cornford.


    What I wanted to do was have (''+new MyDate) give the same result as
    (''+new Date), with (new MyDate) and (new Date) still giving the same
    values for .toString() and .valueOf().

    I managed to accomplish this by having (new MyDate).valueOf() return a
    new Number object instead of a number primitive, which seems to force
    toString() as the default value... you can probably explain how this
    works much better than I can though.

    http://groups.google.com/group/comp.lang.javascript/msg/204f2f2d2fdb5403
    nick, Apr 23, 2010
    #9
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Peter Grison

    Date, date date date....

    Peter Grison, May 28, 2004, in forum: Java
    Replies:
    10
    Views:
    3,229
    Michael Borgwardt
    May 30, 2004
  2. steve
    Replies:
    4
    Views:
    514
    Brian van den Broek
    Mar 13, 2005
  3. Mike Rooney
    Replies:
    1
    Views:
    277
  4. Sir Wilhelm the Sturdy

    Subclassing datetime.date

    Sir Wilhelm the Sturdy, Feb 6, 2010, in forum: Python
    Replies:
    2
    Views:
    228
    Gabriel Genellina
    Feb 7, 2010
  5. none
    Replies:
    2
    Views:
    88
    Steven Jenkins
    Jul 7, 2005
Loading...

Share This Page