Lexical Scope (Static Scope)

Lexical scope is scope that makes the declared resources (variables, functions and objects) available only to the function they were declared in, and to any of its nested child functions

Lexical scope is the scope that exists at lexing time. When a JS closure is made it keeps references to its lexical scope. Hoisting is a result of the process of lexical scoping.

Lexing time

Is where the computer takes JS code and changes it to a computer readable format. The lexing process starts with the innermost functions and works it’s way outward from there. It looks for any resources being used and tries to find where they were declared, in order to construct the scope.

"This is the same mechanism which results in “hoisting” variables. The variables are not actually moved within the source code, the declarations simply occur during the lexing phase and so the JavaScript engine is aware of these before execution." - astronautweb.co
// split into two separate steps at lexing time
var a = 2;

// Declares the variable in the scope, before code execution.
var a 
// assigns the value 2 to the variable a, if it is found in the available scope
a = 2


var a = 1;
// a: 1
console.log('a:', a);

// This variable is undefined but it's indentifier exists
// a: undefined
console.log('a:', a);
var a = 1;

// This variable doens't exist at all
// Uncaught ReferenceError: a is not defined
console.log('a:', a);

This demonstrates that during the lexing phase, the JavaScript engine declares the variables first, before the following step in which the values are assigned to the identifiers (hoisting). Because functions are also defined at this time (lexing phase), we can say that lexical scope is based on where variables and blocks of scope exist at author time, and thus are locked down at the end of the lexing phase. Scope is not defined at runtime, rather it can be accessed at runtime. - astronautweb.co

Function Scope

A function scope is created for every function that is created. It also inherits from top level and global scopes.

function iHaveScope() {
  // local function scope
  const a = 2;
  function iHaveNestedScope() {
    // nested local function scope
    const b = 3;
    // 2
  // Undefined

Block Scope

Block scopes are what you get when you use if statements, for statements, etc.

// undefined object in a block scope
{ var a }

if (3 == '3') {
  // block scope for the if statement

for (var i=0; i<10; i++) {
  // block scope for the for statement

Variables in block and function scope

Accessibility of var in block and function scope.

function soemthing() {
  var a = 1;
// not defined

for (var i=0; i<10; i++) {}
// 10

You can use let to protect variables within a block scope.

for (let i=0; i<10; i++) {
  // block scope for the for statement
// undefined