An example of Scheme program without hoisting:
(define x 10) ; global `x`
(print x) ; 10
((lambda ()
(print x) ; still 10, not shadowed yet
(define x 20) ; local `x`, shadows the global `x`
(print x))) ; 20
(print x) ; still 10, outer not changed
An example of JavaScript program using var
keyword:
var x = 10; // global `x`
console.log(x); // 10
(function() {
console.log(x); // undefined (shadowed, and hoisted)
var x = 20; // update of the local
console.log(x); // 20
})();
console.log(x); // 10
Note: TDZ (Temporal Dead Zone) -- a region of a program, where a variable cannot be accessed.
An example of ES6 program using let
keyword:
let x = 10; // global `x`
console.log(x); // 10
(function() {
console.log(x); // shadows outer, TDZ: Reference Error, "x" is not defined
let x = 20; // init the local
console.log(x); // 20
})();
console.log(x); // 10
Notes:
- In the "no hoisting, no shadow" system (example 1): it's not possible to access a variable before it's definition. However, it doesn't shadow the outer var before actual inner var definition;
- In the "shadow, TDZ" (example 3): it is also not possible to access the variable before its definition, however, it shadows the outer variable on entering the scope, still hoisting the (uninitialized) binding, but under the TDZ.
- In the "shadow, hoisting" (example 2): it is possible to access a variable before it's definition, since it's hoisted on entering scope (shadowing the outer) and is assigned a default value
undefined
.