Scope is the region of code where a name is visible. Code can read variables from enclosing scopes but not from inner ones, and an inner declaration with the same name shadows the outer one. let, const and class are block-scoped to the nearest {...}; var is function-scoped, ignores blocks and may be redeclared. A const binding cannot be reassigned, but its object can still change (see Object.freeze(), Descriptors and Freezing).

let color = "red";
function paint() {
var shade = "light"; // function scope
if (true) {
var shade = "dark"; // same variable: var ignores blocks
let color = "blue"; // new block variable shadows the outer one
const size = 10;
}
console.log(shade, color, typeof size);
}
paint();
try { total = 1; } catch (e) { console.log(e.message); } // no implicit globals
const fns = [];
for (var i = 0; i < 3; i++) fns.push(() => i); // one shared i
for (let j = 0; j < 3; j++) fns.push(() => j); // a fresh j per iteration
console.log(fns.map((fn) => fn()).join(" "));dark red undefined total is not defined 3 3 3 0 1 2
In a sloppy-mode classic script, assigning to an undeclared name silently creates a global, and a top-level var becomes a property of window; modules and strict mode (Strict Mode) throw instead.