0

/* Hoisting exampe - let */
let a = 100;
{
 console.log(a); // 100
}
{
 console.log(a); // ReferenceError: a is not defined
 let a = 50;
}

/* Hoisting took place in {}. */
{
 let a=100;
 console.log(a); // 100
}
console.log(a); // ReferenceError: a is not defined

First, I know that let andconst have a block scope.
Compilation happens in Execution context units, and hoisting occurs when LexicalEnvironment is created.
And the execution context is created by the execution of global, function, eval code.

Shouldn't hoisting of const andlet be done in global, function, eval code units?
(It seems that hoisting doesn't seem to happen, but this is purely thanks to the help of TDZ. Internally both const and let hoisting.)

If engine meet block {/* code */} (rather than function) while creating Execution Context, are engine adding a new scope for the block to [[Scope]]?

CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
redchicken
  • 311
  • 1
  • 5
  • 18
  • You can find answer for let : https://stackoverflow.com/questions/762011/whats-the-difference-between-using-let-and-var?rq=1 – Ray Jan 20 '20 at 05:58

1 Answers1

1

When a block is first encountered (with the {), a new execution context is created, which creates a new empty Lexical Environment (which is basically a container mapping variable names in the current immediate scope to their values). The engine then iterates through all variables declared with const or let in the immediate block are initialized. (But, despite being initialized, they aren't referenceable until the engine actually comes across the const <variableName> or let <variableName> line - the TDZ)

So, plain blocks do create a new scope, which will get populated if any statements immediately inside that block declare a variable with const or let.

You can see this in action with a debugger:

/* Hoisting took place in {}. */
{
    debugger;
    let a=100;
    console.log(a); // 100
}
console.log(a); // ReferenceError: a is not defined

Result in Chrome devtools:

enter image description here

(though, that's a bit misleading - a doesn't actually contain undefined, it hasn't been fully created at that point)

The const and let variable names are hoisted in that the interpreter recognizes from the start of the block that it'll be illegal to reference them until they get fully created via the const or let line.

It's not just plain blocks - any level of code will result in the same sort of thing happening (like at the top level, or inside a for block, or inside a function).

CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
  • Thanks for the very very detailed answer. Images and code help me to understand the text. However, as I studied more recently, I felt different from CertainPerformance's answer. CertainPerformance said that **Execution context** also occurs when they meet `{...}`. **Execution context** is not new, but is it that `[[scope]]` (scope chain) inside **Execution context** provides scope and chaining for information in `{...}` ? – redchicken Jan 23 '20 at 16:39