Hoisting refers to the notion that variable declarations are hoisted a to the top of the variable scope.
More accurately, it is a side effect of the a fact that JavaScript builds it's execution environment in two passes.
The first pass sets up all function and variable declarations. At this stage, variables are declared but not defined, function declarations are declared and defined (that's function declarations: function fnName(){...}
not variable function expressions: var fnName = function (){...}
).
The second pass then executes the code with the available declared functions and variables (which currently are unassigned and therefore have the value undefined).
var
is function scoped and not block scoped.
Although let
andconst
allow the declaration of block scoped variables, the code is built using the two execution passes. The difference being that block scope should be considered in the first pass within their own scope (block scope or otherwise).
To illustrate this point, consider your second snippet.
The code throws an error in your second case because after the first pass it could be re-written as:
// const 'a' declared in this outer scope
const a:
a = 1;
{
// separate const 'a' declared in this block scope
// Declarations still hoisted for this block scope
const b, a
b = a; // a undefined here
a = 2;
}