demosthenes
demosthenes

Reputation: 1191

javascript: pass arguments to object constructor

i am writing a jquery lib and i need to implement Datetime functions. i need to create a .Date() function which return a new Date object.

How to pass arguments of my .Date(args) function to Date object constructor so to create a new date object?

i tried something like this, me is the plugin namespace, me=$.jqGUI.

        //.Date(Value)
        /* Return a date object.
         * ReturnValue = Date(Value)
         */
        me.Date = function(Value){
            //pass arguments to Date constructor
            var sDate = Date.prototype.constructor.apply(null, arguments);

            console.log(sDate);

            //create a date object d
            var d = new Date(sDate);

            //validate date object
            if(d.toDateString()=="Invalid Date"){
                throw new Error("$.jqGUI.Date: Invalid Date");
            }
            else{
                return d;                   
            }
        };

here i pass to Date.prototype.constructor the arguments but i get in any case the current date. if arguments is a date string it is ignored. why?

Upvotes: 4

Views: 8827

Answers (5)

clockworkgeek
clockworkgeek

Reputation: 37700

A few notes:

  • Never use eval, it is dangerous.
  • bind isn't always available and as pointed out, shims don't work the same.
  • Date.UTC also takes a variable argument list and returns a scalar that can be used by the Date constructor.
  • apply only requires an array like object, not an actual array, so arguments is good enough.

So here is my preferred, browser safe, totally variable method. Notice how it handles no arguments with Date.now(). Passing a null is not the same as no arguments so that is allowed to perform the same.

me.Date = function(value){
    if (arguments.length < 1) value = Date.now();
    else if (arguments.length > 1) value = Date.UTC.apply(null, arguments);
    var d = new Date(value);

    // ...
}

Upvotes: 0

user2683246
user2683246

Reputation: 3568

var args = Array.prototype.concat.apply([null], arguments);
return new (Function.prototype.bind.apply(Date, args));

If your target browser doesn't support ECMAScript 5 Function.prototype.bind, the code won't work. It is not very likely though, see compatibilty table.

Upvotes: 7

Andrew GS
Andrew GS

Reputation: 11

The accepted answer is not ideal. I can only hope that anyone reading this thread will investigate further. Using 'eval' has a host of side-affects that I don't think you would want in a util-lib.

Here's a rough take at what you could do:

function dateShimmer() {  
    if(arguments.length === 1){
        return new Date(arguments[0]);
    }
    else if(arguments.length > 1){
        return dateArgumentShimmer.apply(null, arguments);
    }
    return new Date();
}

function dateArgumentShimmer(a1, a2, a3, a4, a5, a6, a7){
    //Direct invocation is faster than apply/call
    switch(arguments.length){
    case 2:  return new Date(a1, a2);
    case 3:  return new Date(a1, a2, a3);
    case 4:  return new Date(a1, a2, a3, a4);
    case 5:  return new Date(a1, a2, a3, a4, a5);
    case 6:  return new Date(a1, a2, a3, a4, a5, a6);
    case 7:  return new Date(a1, a2, a3, a4, a5, a6, a7); 
    }
 }; 

Jsfiddle here: http://jsfiddle.net/y7Zmr/

Upvotes: -1

Bergi
Bergi

Reputation: 664195

Date.prototype.constructor

is quite useless, just use Date - the function is the constructor.

.apply(null, ...

You will need to apply a constructor on a newly created object of that type, not on null. See Use of .apply() with 'new' operator. Is this possible?

However, it is impossible to apply the real Date constructor (the function used for new), because EcmaScript specifies that when Date is called as a function it must return the current UTC time.


Anyway, you should not need this. Instead of receiving a bunch of arguments (of variable size), you should just specify a parameter to be a Date object. The user of the function can build that how he wants.

Your odd-looking function seems to do exactly the same as the Date constructor. Throw it away, and let the user apply Date himself - he knows which format he wants.

Also, you should not use if(d.toDateString()=="Invalid Date"), this is not standardisized but implementation-dependent. To check for a valid Date object, just use isNaN - the internal representation (valueof the Date instance) of unparsable dates is NaN.

Suggestion:

me.date = function(d) {
/* gets: a Date object or something that can be transformed to a Date
returns: a valid Date object, else throws an Error */

    d = new Date(d); // works also for Date instances, uncouples them
                     // else creates new one from string or number
    if (isNaN(d))
        throw new Error("$.jqGUI.Date: Invalid Date");
    return d;
};

Upvotes: 2

demosthenes
demosthenes

Reputation: 1191

ok for me the following was worked

var args = [];
for(var i = 0; i < arguments.length; i++)
   args.push("arguments[" + i + "]");

var d = eval("new Date(" + args.join(",") + ")");   

Upvotes: -2

Related Questions