6

I'm following John Resig's Secrets of JS ninja slides and I've found something I don't clearly understand. Following code defines a named function expression:

var ninja = function myNinja(){
  console.log(myNinja); // function myNinja() {...}
};
myNinja; // undefined

As I can see, in the current scope (suppose it's global), ninja is the variable that holds reference to the named function myNinja. ninja variable is accessible in the scope - that's clear, but myNinja is not accessible in the scope (but it's accessible inside its own function). How come?

If I define a function (not using a function expression, but function declaration):

function Cheese() {
  console.log(Cheese);
}

then it's accessible in the current scope. I know that this just works like that - but can someone explain why is that?

ducin
  • 25,621
  • 41
  • 157
  • 256
  • 2
    http://kangax.github.io/nfe/#named-expr – zerkms Jul 03 '13 at 11:25
  • *"can someone explain why is that"* If you are asking for the reason for this design decision, you should contact someone working at the ECMAScript standard. – Felix Kling Jul 03 '13 at 11:28
  • @FelixKling Hi,see you again! Are you copy comment from my question? – yuan Jul 03 '13 at 11:30
  • @FelixKling well, it's not about design decisions :) I just want to understand how does this concept work internally, not why did someone in ECMA like this concept ;) – ducin Jul 03 '13 at 11:33
  • 1
    @tkoomzaaskz: In that case, you can find the technical explanation in the specification: http://es5.github.io/#x13. It explicitly says: *"The `Identifier` in a `FunctionExpression` can be referenced from inside the `FunctionExpression`'s `FunctionBody` to allow the function to call itself recursively. However, unlike in a `FunctionDeclaration`, the `Identifier` in a `FunctionExpression` cannot be referenced from and does not affect the scope enclosing the `FunctionExpression`."* – Felix Kling Jul 03 '13 at 11:38
  • @yuan: I put the comment wherever I see fit ;) – Felix Kling Jul 03 '13 at 11:38

4 Answers4

4

In his book, The Secrets of the JavaScript Ninja, John Resig makes a wonderful explanation about this concept.

http://jsninja.com/

Below are the quotes from the book:

4.2.4. Inline named functions

 <script type="text/javascript">
  var ninja = function myNinja(){ 
      assert(ninja == myNinja, "this is named two things at once!"); 
  };
  ninja(); 
  assert(typeof myNinja == "undefined",
    "But myNinja isn't defined outside of the function."); 
 </script>

This listing brings up the most important point regarding inline functions: even though inline functions can be named, those names are only visible within the functions themselves.

Remember the scoping rules we talked about back in chapter 3? Inline function names act somewhat like variable names, and their scope is limited to the function within which they’re declared.

3.2.1. Scoping and functions

Variable declarations are in scope from their point of declaration to the end of the function within which they’re declared, regardless of block nesting.

If you would like to know more about this concept, this book will help you.

naota
  • 4,695
  • 1
  • 18
  • 21
1

why is that?

A function expression creates a new function object every time it is evaluated. What happens with that result is irrelevant at first. But…

var ninja;
// myNinja; - what would you expect it to be here?
for (var i=0; i<5; i++)
    ninja = function myNinja(){
        console.log(myNinja);
    };
// myNinja; - *which one* would you expect it to be here?
ninja();

The call to ninja() is obvious, it references the function that was assigned to that variable at last. And the myNinja in the console.log references the current function object - it's in its own scope.

But the myNinja identifier would be ambiguous outside the function itself.

In contrast, a function declaration is hoisted and accessible from the whole scope. Its identifier uniquely refers to the single function object which is created once in the initialisation of the scope.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
0

Imagine that when you simply define a function (cheese), you tell the current scope - "I want you to know this function, it's name is cheese. when you use the var ninja, you're dealing the ninja scope now, telling it basically the same thing. so now you new function (myNinja) is know only at the current (ninja) scope...

Oded
  • 145
  • 1
  • 7
  • I'm trying to understand your explanation. I know that when control goes into a new function in javascript, new scope context is created and new variable object is attached to it - that's clear. Now you wrote: _when you use the var ninja, you're dealing the ninja scope now_ - do you mean that when I declare a new variable (and in this case the variable refers to a function) there's a new scope for the variable (not a function)? – ducin Jul 03 '13 at 11:36
0

Name is a property of the function object. If you were to inspect a Function instance in the debugger, you will see a name property on it. In the case of functions that are defined in the global scope, the value of name is automatically used as the name of the property of the window object by which it is referenced.

In the case of an inline function, you are defining the name of the property by which the function will be referenced. The JS engine does not need to use the name property from the Function instance.

Pranav Negandhi
  • 1,594
  • 1
  • 8
  • 17