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 JavaScr
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.
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.
There is nothing magical about functions and constructors. All objects in JavaScript are … well, objects. But some objects are more special than the others: namely built-in objects. The difference lies mostly in following aspects:
null
and undefined
are special objects. Any attempt to use a method on these objects or define new methods causes an exception.+
, -
, *
, /
.+
.()
, and the new
operator. The latter has the innate knowledge on how to use the prototype
property of the constructor, construct an object with proper internal links to the prototype, and call the constructor function on it setting up this
correctly.If you look into the ECMAScript standard (PDF) you will see that all these "extra" functionality is defined as methods and properties, but many of them are not available to programmers directly. Some of them will be exposed in the new revision of the standard ES3.1 (draft as of 15 Dec 2008: PDF). One property (__proto__
) is already exposed in Firefox.
Now we can answer your question directly. Yes, a function object has properties, and we can add/remove them at will:
var fun = function(){/* ... */};
fun.foo = 2;
console.log(fun.foo); // 2
fun.bar = "Ha!";
console.log(fun.bar); // Ha!
It really doesn't matter what the function actually does — it never comes to play because we don't call it! Now let's define it:
fun = function(){ this.life = 42; };
By itself it is not a constructor, it is a function that operates on its context. And we can easily provide it:
var context = {ford: "perfect"};
// now let's call our function on our context
fun.call(context);
// it didn't create new object, it modified the context:
console.log(context.ford); // perfect
console.log(context.life); // 42
console.log(context instanceof fun); // false
As you can see it added one more property to the already existing object.
In order to use our function as a constructor we have to use the new
operator:
var baz = new fun();
// new empty object was created, and fun() was executed on it:
console.log(baz.life); // 42
console.log(baz instanceof fun); // true
As you can see new
made our function a constructor. Following actions were done by new
:
{}
) was created.fun.prototype
. In our case it will be an empty object ({}
) because we didn't modify it in any way.fun()
was called with this new object as a context.It is up to our function to modify the new object. Commonly it sets up properties of the object, but it can do whatever it likes.
Fun trivia:
Because the constructor is just an object we can calculate it:
var A = function(val){ this.a = val; };
var B = function(val){ this.b = val; };
var C = function(flag){ return flag ? A : B; };
// now let's create an object:
var x = new (C(true))(42);
// what kind of object is that?
console.log(x instanceof C); // false
console.log(x instanceof B); // false
console.log(x instanceof A); // true
// it is of A
// let's inspect it
console.log(x.a); // 42
console.log(x.b); // undefined
// now let's create another object:
var y = new (C(false))(33);
// what kind of object is that?
console.log(y instanceof C); // false
console.log(y instanceof B); // true
console.log(y instanceof A); // false
// it is of B
// let's inspect it
console.log(y.a); // undefined
console.log(y.b); // 33
// cool, heh?
Constructor can return a value overriding the newly created object:
var A = function(flag){
if(flag){
// let's return something completely different
return {ford: "perfect"};
}
// let's modify the object
this.life = 42;
};
// now let's create two objects:
var x = new A(false);
var y = new A(true);
// let's inspect x
console.log(x instanceof A); // true
console.log(x.ford); // undefined
console.log(x.life); // 42
// let's inspect y
console.log(y instanceof A); // false
console.log(y.ford); // perfect
console.log(y.life); // undefined
As you can see x
is of A
with the prototype and all, while y
is our "naked" object we returned from the constructor.
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.
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.
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:
- Define the object type by writing a function.
- 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
.