views:

1340

answers:

8

I have been doing a lot of research on this lately, but have yet to get a really good solid answer. I read somewhere that a new Function() object is created when the JavaScript engine comes across a function statement, which would lead me to believe it could be a child of an object (thus becoming one). So I emailed Douglas Crockford, and his answer was:

Not exactly, because a function statement does not call the compiler.

But it produces a similar result.

Also, to my knowledge, you can't call members on a function constructor unless it has been instantiated as a new object. So this will not work:

function myFunction(){
    this.myProperty = "Am I an object!";
}
myFunction.myProperty; // myFunction is not a function
myFunction().myProperty; // myFunction has no properties

However, this will work:

function myFunction(){
    this.myProperty = "Am I an object!";
}
var myFunctionVar = new myFunction();
myFunctionVar.myProperty;

Is this just a matter of semantics... in the whole of the programming world, when does an object really become an object, and how does that map to JavaScript?

+3  A: 

The "global" scope of Javascript (at least in a browser) is the window object.

This means that when you do this.myProperty = "foo" and call the function as plain myFunction() you're actually setting window.myProperty = "foo"

The second point with myFunction().myProperty is that here you're looking at the return value of myFunction(), so naturally that won't have any properties as it returns null.

What you're thinking of is this:

function myFunction()
{
    myFunction.myProperty = "foo";
}

myFunction();
alert(myFunction.myProperty); // Alerts foo as expected

This is (almost) the same as

var myFunction = new Function('myFunction.myProperty = "foo";');
myFunction();

When you use it in the new context, then the "return value" is your new object and the "this" pointer changes to be your new object, so this works as you expect.

Greg
This is probably the best description of that concept I have ever read. Thanks for posting!
hal10001
A: 

JavaScript is based on the ECMA script. Its specification uses the prototyping model for it to be OOP. How ever, ECMA script does not enforce strict data types. The object needs to be instantiated for the same reason that ECMA script requires a 'new' call which will allocate memory for the property, Otherwise it will remain a function and you can call it if you like, in which case, the property will initialize and then be destroyed when the function ends.

fasih.ahmed
+5  A: 

To answer your specific question, technically functions are always objects.

For instance, you can always do this:

function foo(){
  return 0;
}
foo.bar = 1;
alert(foo.bar); // shows "1"

Javascript functions behave somewhat like classes in other OOP languages when they make use of the this pointer. They can be instantiated as objects with the new keyword:

function Foo(){
  this.bar = 1;
}
var foo = new Foo();
alert(foo.bar); // shows "1"

Now this mapping from other OOP languages to Javascript will fail quickly. For instance, there is actually no such thing as classes in Javascript - objects use a prototype chain for inheritance instead.

if you're going to do any sort of significant programming in Javascript, I highly recommend Javascript: The Good Parts by Crockford, that guy you emailed.

Triptych
+1  A: 

First, JavaScript doesn't behave the same way about objects as C++/Java does, so you need to throw those sorts of ideas out of the window to be able to understand how javascript works.

When this line executes:

var myFunctionVar = new myFunction();

then the this inside of myFunction() refers to this new object you are creating - myFunctionVar. Thus this line of code:

 this.myProperty = "Am I an object!";

essentially has the result of

 myFunctionVar.myProperty = "Am I an object!";

It might help you to take a look at some documentation on the new operator. In JS, the new operator essentially allows you to create an object out of a function - any plain old function. There is nothing special about the function that you use with the new operator that marks it as a constructor, as it would be in C++ or Java. As the documentation says:

Creating a user-defined object type requires two steps:

  1. Define the object type by writing a function.
  2. Create an instance of the object with new.

So what you have done with the code

function myFunction(){
    this.myProperty = "Am I an object!";
}

is to create a function that would be useful as a constructor. The reason why the code myFunction.myProperty fails is that there is no reference named myFunction.

matt b
+8  A: 

Your understanding is wrong:

myFunction().myProperty; // myFunction has no properties

The reason it does not work is because ".myProperty" is applied to the returned value of "myFunction()", not to the object "myFunction". To wit:

$ js
js> function a() { this.b=1;return {b: 2};}
js> a().b
2
js>

Remember, "()" is an operator. "myFunction" is not the same as "myFunction()". You don't need a "return" when instanciang with new:

js> function a() { this.b=1;}
js> d = new a();
[object Object]
js> d.b;
1
niXar
hey is that a command-line javascript interpreter? where can i get one? seems a lot easier than using firebug console to test something
matt b
Just did "yum install js"; it's actually spidermonkey, Firefox js engine compiled as a command line executable. If you use a lesser operating system, you can always use rhino, the Java version.
niXar
A: 

Only when you instantiate with the new keyword does the function act as a constructor.

The result is an object that can use the "this" keyword to access member properties. The this keyword in the method does not make any sense when the function is used any other way.

Kekoa
+4  A: 

Indeed, Functions are 'first class citizens': they are an Object.

Every object has a Prototype, but only a function's prototype can be referenced directly. When new is called with a function object as argument, a new object is constructed using the function object's prototype as prototype, and this is set to the new object before the function is entered.

So you could call every function a Constructor, even if it leaves this alone.

There are very good tutorials out there on constructors, prototypes etc... Personally I learned a lot from Object Oriented Programming in JavaScript. It shows the equivalence of a function which 'inherits' its prototype, but uses this to fill in a new object's properties, and a function object that uses a specific prototype:

function newA() { this.prop1 = "one"; } // constructs a function object called newA
function newA_Too() {} // constructs a function object called newA_Too
newA_Too.prototype.prop1 = "one";

var A1 = new newA();
var A2 = new newA_Too();
// here A1 equals A2.
xtofl
+6  A: 
Eugene Lazutkin