skip to Main Content

Here are the simple code:

{
  function a() {}
  a = "test";
}

console.log(a);

I expected to get "test" but got "ƒ a() {}" in console. Why is that? Can anyone explain this behaviour?

3

Answers


  1. It’s because you are only re-assigning "a" in local scope. Run this code and look at the console logs to see what exactly is going on:

    // Reference the global scope
    var self = this;
    
    {
      function a() {}
      console.log("Function a declared!")
      console.log("A in local scope: "+ a);
      console.log("A in global scope: "+ self.a);
      a = "test";
      console.log("Reassigned A!")
      console.log("A in local scope: "+ a);
      console.log("A in global scope: "+ self.a);
    }
    
    console.log("Printing in global scope!")
    console.log("A in local scope: "+ a);
    console.log("A in global scope: "+ self.a);

    If you look at the official docs, it states: "Function declarations in JavaScript are hoisted to the top of the enclosing function or global scope." function#hoisting

    Since there is no enclosing function, just a block, the function gets hoisted to the global scope.

    I couldn’t find any official documentation regarding the exact behaviour of implicit globals. (Best I could find is: var#implicit_globals_and_outer_function_scope Therefor I can only assume that it searches for the closest scope to reassign. As the function is declared in local scope of the block, it only reassigns the local scoped function declaration and not the one hoisted to global scope.

    Login or Signup to reply.
  2. Our code works in the non-strict mode so some quirk things happen (it’s legacy).

    Please use the strict mode only, which throws an error and prohibits such strange effects that lead to bugs.

    {
      /* in the non-strict mode a function is declared in a block
         (creating a local variable)
         but also hoisted to the global scope 
      */
      function a() {} 
      a = "test"; // this assigns to the local variable, not affecting the hoisted one
    }
    
    console.log(a); // prints the hoisted variable

    The strict mode:

    'use strict';
    {
      function a() {} 
      a = "test"; 
    }
    
    console.log(a);
    Login or Signup to reply.
  3. Sloppy mode vs Strict Mode

    It has to do with strict and quirks mode in modern browsers, and that the effect of defining a function (which used to be always hoisted to the scope of the the function it’s in) inside a block statement.

    1. In modern browsers in strict mode, the function is defined with block scope only, and the value of a is modified by the assignment. Outside the block a remains undefined.
    "use strict";
    {
      function a() {}
      a = "test";
      console.log("Inside strict mode block after assignment:")
      console.log(a);
    }
    
    console.log("Outside block a is undefined");
    console.log(a);
    1. In quirks mode however (without "use strict"), browsers seem to hoist the function definition to function scope, but still keep a binding for a inside the block. The practical effect is that the hoisted function definition remains in place outside the block, while inside the block, the local value of a is updated by the assignment.
    {
      function a() {}
      a = "test";
      console.log("Inside block after assignment:")
      console.log(a);
    }
    
    console.log("Outside block a is the hoisted function");
    console.log(a);

    I believe the behavior in quirks mode was arrived at to maintain some similarity with browser behavior prior to the introduction possibly block scoping variables – _if you don’t overwrite the function name with

    Bottom line? _The handling of defining functions within the block of a conditional or loop statement (using { and } delimiters) prior to ES5 was not standardized. Many people would not have done it for stylistic reasons – why define a function name that will be hoisted inside a block. Which left the door open to not hoist function names outside the block in strict mode.

    Moral of the story – don’t write serious code in sloppy mode 🙂

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search