Search code examples
javascripthoisting

Function names defined as parameters to a function call aren't hoisted. Why not?


Consider the following code.

<!DOCTYPE html>
<script>
  console.log(a);
  function a() {}
</script>

Notice that a is seemingly accessed before it is defined. The console output is: (jsfiddle)

function a() {}

Function and variable names are defined before any other code runs, so the console.log call works here. This is called hoisting.

But this doesn't work if the function is defined as a parameters in a function call. Look at this code.

<!DOCTYPE html>
<script>
  function a() {}
  a(function b() {});
  console.log(b);
</script>

Notice that the function b is defined inside of a call to a. Not inside of a closure, but inside of a call. The console output is: (jsfiddle)

Uncaught ReferenceError: b is not defined

I'm wondering why this happens. Is this the intended behavior? This happens in both Chrome and Firefox.

UPDATE: This jsfiddle shows that names in function expressions are never available in the scope in which they are defined. However, the name is defined inside the scope of the function itself. This means a named function expression can refer to the name, but only inside the function. The name is also stored in the function's name parameter.

<!DOCTYPE html>
<script>
  console.log(a); // undefined
  var a = function b() {
    console.log(b); // function b() { … };
  };
  a(); // function b() { … };
  console.log(a); // function b() { … };
  console.log(a.name); // b
  console.log(b); // Uncaught ReferenceError: b is not defined
</script>

Solution

  • Inside a(function b() {});, the function is a function expression and not a function declaration (only which are hoisted). You might have a look at var functionName = function() {} vs function functionName() {} for the difference.