Skip to content Skip to sidebar Skip to footer

Why In JavaScript Is A Function Considered Both A Constructor And An Object?

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 eng

Solution 1:

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:

  1. General treatment of objects. Examples:
    • Numbers and Strings are immutable (⇒ constants). No methods are defined to change them internally — new objects are always produced as the result. While they have some innate methods, you cannot change them, or add new methods. Any attempts to do so will be ignored.
    • null and undefined are special objects. Any attempt to use a method on these objects or define new methods causes an exception.
  2. Applicable operators. JavaScript doesn't allow to (re)define operators, so we stuck with what's available.
    • Numbers have a special way with arithmetic operators: +, -, *, /.
    • Strings have a special way to handle the concatenation operator: +.
    • Functions have a special way to handle the "call" operator: (), 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:

  1. New empty object ({}) was created.
  2. Its internal prototype property was set to fun.prototype. In our case it will be an empty object ({}) because we didn't modify it in any way.
  3. 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.


Solution 2:

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

Solution 3:

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.


Solution 4:

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.


Solution 5:

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.

Post a Comment for "Why In JavaScript Is A Function Considered Both A Constructor And An Object?"