fredrik
fredrik

Reputation: 17617

Why does local variable names take precedence over function names in JavaScripts?

In JavaScript you can define function in a bunch of different ways:

function BatmanController () {
}

var BatmanController = function () {
}

// If you want to be EVIL
eval("function BatmanController () {}");

// If you are fancy
(function () {
    function BatmanController () {
    }
}());

By accident I ran across a unexpected behaviour today. When declaring a local variable (in the fancy way) with the same name as function the local variable takes presence inside the local scope. For example:

(function () {
    "use strict";

    function BatmanController () {
    }

    console.log(typeof BatmanController); // outputs "function"

    var RobinController = function () {
    }

    console.log(typeof RobinController); // outputs "function"

    var JokerController = 1;
    function JokerController () {

    }
    console.log(typeof JokerController); // outputs "number", Ehm what?
}());

Anyone know why var JokerController isn't overwritten by function JokerController? I tested this in Chrome, Safari, Canary, Firefox. I would guess it's due to some "look ahead" JavaScript optimizing done in the V8 and JägerMonkey engines. But is there any technical explanation to explain this behaviour?

Upvotes: 1

Views: 365

Answers (2)

Elias Van Ootegem
Elias Van Ootegem

Reputation: 76413

The way you declare the JokerController function causes the function definition to be hoisted to the top of the scope. In other words, the code that is actually run looks like this:

 function JokerController (){}
 var JokerController = 1;

If you declare a function as an anonymous function object, referenced/assigned to a variable, then the function definition is part of an expression, and therefore cannot be hoisted top the top of the current scope.

See paragraph titled Function on MDN

Upvotes: 1

James Allardice
James Allardice

Reputation: 166021

Because function and variable declarations are hoisted to the top of the scope in which they occur, yet assignments happen in place. Your code is effectively interpreted as this:

(function () {
    "use strict";

    function BatmanController () {} // Declarations are hoisted
    function JokerController () {}

    var RobinController, // Declarations are hoisted
        JokerController;

    RobinController = function () {} // Assign function to RobinController

    // outputs "function" (declaration was hoisted to top of scope)
    console.log(typeof BatmanController);

    // outputs "function" (assignment of number hasn't happened yet)
    console.log(typeof RobinController);

    JokerController = 1; // Assign number to JokerController

     // outputs "number" (assignment of number has now happened)
    console.log(typeof JokerController);
}());

For the full technical details I suggest you read section 10.5 of the spec.

Upvotes: 4

Related Questions