How does this hoisting work with block scope?

Hao Wu

I've been asked about a question

{
  function foo() {
    console.log('A');
  }
  
  foo();
  
  foo = 1;
  
  function foo() {
    console.log('B');
  }
  
  foo = 2;

  console.log(foo);
}
console.log(foo);

Why the third output is 1 instead of 2?


There should be no block scoped foo being created since there is neither let nor const in that block. But the second foo output is 2 means there is indeed another reference of foo has been created.

What is going on?

P.S. I'm using Chrome Version 89.0.4389.90 (Official Build) (x86_64).

Jonas Wilms

According to the web compat semantics at the place of the function declaration, the value of the blocked scope variable is bound to the outer scope². This code is equivalent to:

let outerFoo; // the functions create a binding outside of the scope

{
  let innerFoo; // but also inside
  // due to hoisting, functions get bound before any code get's executed:
  innerFoo = function foo() {
    console.log('A');
  };
  innerFoo =   function foo() {
    console.log('B');
  };
  
  // At the place of the function declaration, the variable leaves the scope
  /* function foo() {
    console.log('A');
  } */
  outerFoo = innerFoo;

  innerFoo();
  
  innerFoo = 1;
  
  // this also applies to the second declaration
  /* function foo() {
    console.log('B');
  } */
  outerFoo = innerFoo;
  
  innerFoo = 2;

  console.log(innerFoo);
}
console.log(outerFoo);

²This is basically exactly how the specification describes it:

When the FunctionDeclaration f is evaluated, perform the following steps in place of the FunctionDeclaration Evaluation algorithm provided in 15.2.6:
a. Let fenv be the running execution context's VariableEnvironment.
b. Let benv be the running execution context's LexicalEnvironment.
c. Let fobj be ! benv.GetBindingValue(F, false).
d. Perform ! fenv.SetMutableBinding(F, fobj, false).

The specification additionally states:

Prior to ECMAScript 2015, the ECMAScript specification did not define the occurrence of a FunctionDeclaration as an element of a Block statement's StatementList. However, support for that form of FunctionDeclaration was an allowable extension and most browser-hosted ECMAScript implementations permitted them. Unfortunately, the semantics of such declarations differ among those implementations. Because of these semantic differences, existing web ECMAScript code that uses Block level function declarations is only portable among browser implementation if the usage only depends upon the semantic intersection of all of the browser implementations for such declarations

So Safari is probably doing it the way it always did it, while Chrome (and Firefox) follow the specification.

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

From Dev

How does this hoisting work with block scope?

From Dev

How does scope work in Io?

From Dev

How does scope work in Ruby?

From Dev

How does receive block work?

From Dev

How does this block return work?

From Dev

Does Javascript hoisting only consider the first var in a scope?

From Dev

Does Javascript hoisting only consider the first var in a scope?

From Dev

What is the skimlinks scope and how does it work

From Java

How does the scope of variables in julia modules work?

From Dev

How Does Spring Batch Step Scope Work

From Dev

What is the skimlinks scope and how does it work

From Dev

How does $.ajax success scope work?

From Dev

How does $mdDialog work with promise and $scope?

From Dev

how does jsp:useBean scope attribute work?

From Dev

Scope of variables (Hoisting) in Javascript

From Dev

Hoisting and variable scope

From Dev

Hoisting and variable scope

From Dev

How does Ruby's block syntax work?

From Dev

How to scope block of code?

From Dev

Angular $scope does not work

From Dev

Angular $scope does not work

From Dev

Why does it work with $scope but not with `this`?

From Dev

In C, if objects declared at block scope have no linkage, why does function declaration inside main() without "extern" work?

From Dev

Confusion about scope and hoisting in Javascript

From Dev

How to Block SSH Brute Force via Iptables and How does it work?

From Dev

$scope.formName.$setPristine() does not work ; How to reset form in angular?

From Dev

How does $scope.apply() work exactly in AngularJS?

From Dev

how does $scope in controllers work and different ways of declaring controllers?

From Dev

What is the scope of the Single Responsibility Principle and how does it work with DRY?

Related Related

HotTag

Archive