🔗

Function Scope, Block Scope and Lexical Scope

Context vs Scope

Antes de entendermos os diferentes tipos de escopo, precisamos clarear o entendimento sobre a diferença entre contexto e escopo. Apesar de parecerem ter a mesma definição, não são a mesma coisa.
Toda função quando executada tem um contexto e um escopo associados. O escopo nada mais é do que a visibilidade das variáveis para o código. Enquanto podemos nos referir ao contexto como o this que está relacionado ao objeto que a função pertence.

"this" Context

O contexto é determinado pela forma com que a função é executada.
Quando uma função é executada como método de um objeto, this se refere ao objeto em que o método foi chamado
const obj = { foo: function() { return this; } }; obj.foo() === obj; // Output: true
O mesmo princípio se aplica quando executamos uma função usando o operador new, para criar uma instância de um objeto. Dessa forma, this se refere a recém criada instância.
function foo() { alert(this); } const instance = new foo() // foo const anotherInstance = new foo() // foo console.log(instance === anotherInstance) // Output: false
Quando a função executada não está vinculada a um objeto ou construtor, this se refere ao objeto global. Porém, no strict mode, será undefined.

Function Scope

Antes da especificação ES6, da introdução dos statements const e let, e do block scope, só existia uma forma de declarar variáveis: usando var. Consequentemente apenas dois tipos de escopos: function scope e global scope.
Uma variável declarada com var é function scoped, o que significa que só existirá dentro do escopo da função em que foi declarada.
function fn() { var name = "John" console.log(name) // Output: John } console.log(name) // Output: name is not defined
A variável name existe apenas dentro da função fn.
Outros tipos de blocos como if e loops não são considerados como um escopo. Apenas funções.
if(true) { var name = "John" } console.log(name) // Output: "John"
A variável name está disponível fora do bloco if em que foi declarada pois estão no mesmo escopo.

Block Scope

Na especificação ES6, let e const foram introduzidos como formas alternativas de se declarar variáveis e com eles, veio o block scope. No block scope, qualquer bloco de código é considerado um escopo.
Uma função continuará sendo um escopo assim como quando usando var
function fn() { const name = "John" console.log(name) // Output: John } console.log(name) // Output: name is not defined
A diferença é que outros blocos também são considerados como escopo
if(true) { const name = "John" } console.log(name) // Output: name is not defined

Lexical Scope

Escopo léxico permite que em um grupo de funções aninhadas, as funções internas tenham acesso às variáveis e recursos do seu escopo superior. Isso significa que essas funções internas estão vinculadas ao execution context - ver
📃
Call Stack, Execution Context and Heap
- dos seus pais.
function father() { const name = "John" function child() { console.log("Father name", name) // Output: Father name John } }

Referências