0

Why this logs 1 ? It's confusing to me , can anyone please explain?

(function(){

  var hello = () => {
    console.log(1);
  }

  function hello () {
    console.log(2);
  }
  return hello()
})()

2 Answers2

1

Function declarations (statements that start with function functionName( )get hoisted to the top of their enclosing scope, and assign to their function name identifier first, before anything else runs in that scope.. Assignments with = do not.

The fact that it's an arrow function doesn't particularly matter - a function assignment at the same point would produce the same results.

(function(){

  var hello = function() {
    console.log(1);
  }

  function hello () {
    console.log(2);
  }
  return hello()
})()

Your code is equivalent to

(function(){
  // hello identifier gets created at the very beginning
  var hello;
  
  // hoisted function declaration assigns to `hello`:
  hello = function hello () {
    console.log(2);
  }
  
  // assignment with =, not hoisted, assigns to `hello`
  hello = () => {
    console.log(1);
  }
  
  return hello()
})()

I'd recommend using ES2015+ syntax at least, which will help prevent you from making these sorts of accidents - it will forbid re-declarations of variables if you use let or const.

(function(){

  let hello = () => {
    console.log(1);
  }

  function hello () {
    console.log(2);
  }
  return hello()
})()
CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
0

Because:

  • Function declarations create identifiers (more specifically, "bindings") in the same binding environment that var declarations do
  • A var declaration for a binding that already exists is not an error
  • Function declarations are processed upon entry to the function or global scope ("hoisted"), so they assign to the binding first

So your code is creating a binding, assigning a the declared function to it, then overwriting that value with the arrow function. In effect:

(function(){
    // Declaration of the var-scoped binding happens first
    var hello;
    // Then the function declaration is processed, assigning
    // the function to the binding
    hello = function hello() {
        console.log(2);
    };
    // Then the step-by-step code begins and processes
    // the assignment
    hello = () => {
        console.log(1);
    };
    return hello();
})();

Side note: var is effectively deprecated, there's no reason to use it in modern code. Instead, use let or const. They have more rational behavior:

  • They're block-scoped, not function- or global-scoped (unless they appear at the top level of function or global scope)
  • Repeated declarations are an error (including a let or const declaration that would conflict with a var-style declaration like a function declaration)
  • At global scope, they live in an inner scope nested inside the global var scope, and they don't create properties on the global object

Your example would have given you a nice, useful error with let or const:

(function(){
    let hello = () => {
        console.log(1);
    };

    function hello () {
        console.log(2);
    }
    
    return hello();
})()
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875