Search code examples
javascriptiife

Why does a named IIFE result in a ReferenceError outiside of it?


Why did I get ReferenceError: Person is not defined” for the following code?

(function Person() {
  console.log('Hi');
}());
console.log(Person);

Since function Person is run, it is first created. However, I cannot explain why it is not then recognized. My only thought is that IIFE ignores the name they are given.


Solution

  • You get the error because the name of a function created by a function expression is not added to the scope the expression is in. (It is in-scope within the function body, so the name isn't just ignored.) A function declaration creates the name in the scope where it appears, but not a named function expression. That's just how JavaScript is defined.

    If it's important that you stick to using an expression rather than a function declaration (for instance, because expressions are done in the step-by-step processing of the code, whereas declarations are done earlier), you can do it with a variable:

    var Person = function Person() {
        console.log('Hi');
    };
    Person();
    console.log(Person);
    

    And that gets more concise with ES6, because in ES6 you can name a function without using a named function expression:

    var Person = function() {
        console.log('Hi');
    };
    Person();
    console.log(Person);
    

    In ES5, that function wouldn't have a name (except many JavaScript engines gave it one anyway). In ES6, that function does have a name, which is taken from the variable.

    Language designers don't necessarily need a "why" for decisions like not putting the name in scope, but it makes sense when you think of doing things like this:

    // ES5 and earlier
    var x = {
        foo: function foo() { /* ... */ },
        bar: function bar() { /* ... */ },
        baz: function baz() { /* ... */ }
    };
    

    It probably makes sense that the above adds x to the scope, but not foo, bar, and baz.