views:

114

answers:

3

I understand the difference in behavior. Date() returns a String representing the current date, and new Date() returns an instance of the Date object whose methods I can call.

But I don't know why. JavaScript is prototyped, so Date is a function and an object which has member functions (methods) which are also objects. But I haven't written or read any JavaScript that behaves this way, and I'd like to understand the difference.

Can somebody show me some sample code of a function that has a method, returns an instance with the new operator, and outputs a String when called directly? i.e. how does something like this happen?

Date();                   // returns "Fri Aug 27 2010 12:45:39 GMT-0700 (PDT)"
new Date();               // returns Object
new Date().getFullYear(); // returns 2010
Date().getFullYear();     // throws exception!

Very specific request, I know. I hope that's a good thing. :)

A: 

new is a keyword in Javascript (and others) to create a new instance of an object.
Possibly duplicate of http://stackoverflow.com/questions/1646698/what-is-the-new-keyword-in-javascript.
See also this article: http://trephine.org/t/index.php?title=Understanding_the_JavaScript_new_keyword

Lekensteyn
Just a guess here, but I don't think the issue here is that new will return and object. Rather it is the fact that Date() can be called without first creating an instance. (for limited usage, I admit) To get the full date functionality, you need to create an instance with new.
Tom
I know what `new` does (and I think I made this clear in my question). I don't know why the function behaves differently when called as a constructor and as a static function. I want to know the syntax that causes this distinction.
sidewaysmilk
A: 

the 'new' keyworkd will create an instance of the type Date. if you don't use it, you'll end up working with the type alone, which has only a few methods/properties exposed as static, while most of it will be only available to the instance.

Thiago Santos
Yeah. I get that, and I believe I made that obvious in my question. But _how_ do you get it to behave differently in different contexts?
sidewaysmilk
+4  A: 

Most of this is possible to do yourself. Calling the bare constructor without new and getting a string is special for Date per the ECMA spec, but you can simulate something similar for that.

Here's how you'd do it. First declare an object in the constructor pattern (e.g. a function that is intended to be called with new and which returns its this reference:

var Thing = function() {
    // Check whether the scope is global (browser). If not, we're probably (?) being
    // called with "new". This is fragile, as we could be forcibly invoked with a 
    // scope that's neither via call/apply. "Date" object is special per ECMA script,
    // and this "dual" behavior is nonstandard now in JS. 
    if (this === window) { 
        return "Thing string";
    }

    // Add an instance method.
    this.instanceMethod = function() {
        alert("instance method called");
    }

    return this;
};

New instances of Thing can have instanceMethod() called on them. Now just add a "static" function onto Thing itself:

Thing.staticMethod = function() {
    alert("static method called");
};

Now you can do this:

var t = new Thing(); 
t.instanceMethod();
// or...
new Thing().instanceMethod();
// and also this other one..
Thing.staticMethod();
// or just call it plain for the string:   
Thing();
quixoto
But `Thing()` doesn't do anything in a static context. Does Date just detect whether its being called in a static context and return a String instead of an Object? If so, how?
sidewaysmilk
Your edit makes it clear. Thank you.
sidewaysmilk
See update. That's a great question. Per @Crescent's comment on the original question, it looks like `Date` is special. You can achieve something like this yourself as above, but please don't. It's not a common usage idiom in JS.
quixoto
You might want to add a little to the comment for future viewers? Like "invoked with a scope that's neither, such as with .map() or .apply()" Thanks again!
sidewaysmilk