O escopo é um conceito importante para determinar a acessibilidade das variáveis. Este conceito está no cerne dos fechamentos, dividindo as variáveis em globais e locais.
Neste artigo, tentarei explicar em termos simples qual é o escopo em JavaScript.
1. Escopo
Antes de mergulhar nos detalhes do escopo, vamos dar uma olhada em um exemplo rápido.
Digamos que definimos uma variável:
const message = 'Hello'
console.log(message) // 'Hello'
Podemos facilmente enviar seu valor para o console. Isso é claro.
Agora vamos colocar a declaração da variável de mensagem no bloco if:
if (true) {
const message = 'Hello'
}
console.log(message) // ReferenceError: message is not defined
Desta vez, ao tentar acessar a variável, é lançada uma exceção ReferenceError: mensagem não definida.
Por quê isso aconteceu?
Porque o bloco if criou um escopo para a variável de mensagem. E a mensagem só está disponível neste escopo.
Assim, a disponibilidade de variáveis é limitada pelo escopo em que são definidas.
Portanto, o escopo é o escopo das variáveis.
2. Escopo do bloco
Um bloco de código em JavaScript define o escopo das variáveis declaradas com as palavras-chave const e let:
if (true) {
// if
const message = 'Hello'
console.log(message) // 'Hello'
}
console.log(message) // ReferenceError
O primeiro console.log () imprime com segurança o valor da variável da mensagem no console, uma vez que essa variável é acessada no escopo em que está definida.
No entanto, chamar o segundo console.log () gera um erro porque a variável da mensagem não está disponível em seu escopo externo: a mensagem não existe no contexto atual.
O escopo do bloco também é criado nas instruções if, for, while.
Por exemplo:
for (const color of ['green', 'red', 'blue']) {
// for
const message = 'Hi'
console.log(color) // 'green', 'red', 'blue'
console.log(message) // 'Hi', 'Hi', 'Hi'
}
console.log(color) // ReferenceError
console.log(message) // ReferenceError
As variáveis de cor e mensagem existem apenas dentro do bloco for.
O mesmo é verdadeiro para a instrução while:
while (/* */) {
// while
const message = 'Hi'
console.log(message) // 'Hi'
}
console.log(message) // ReferenceError
A mensagem definida em while só está disponível neste loop.
Em JavaScript, você pode criar blocos de código autocontidos. Eles também definem seu próprio escopo:
{
const message = 'Hi'
console.log(message) // 'Hi'
}
console.log(message) // ReferenceError
2.1. var não tem escopo de bloco
Como vimos nos exemplos anteriores, um bloco de código cria escopo para variáveis declaradas com as palavras-chave const e let. No entanto, isso não funciona para variáveis declaradas com a palavra-chave var.
Vamos considerar um exemplo:
if (true) {
// if
var count = 0
console.log(count) // 0
}
console.log(count) // 0
A contagem de variável está disponível dentro do bloco if, como esperado. No entanto, também está disponível fora deste bloco!
Isso ocorre porque o bloco de código não cria escopo para variáveis declaradas com a palavra-chave var. Mas a função faz isso.
3. Escopo da função
As funções em JavaScript criam escopo para todas as variáveis, independentemente da palavra-chave com que são declaradas (var, const ou let).
Por exemplo:
function run() {
// run()
var message = ', , !'
console.log(message)
}
run() // ', , !'
console.log(message) // ReferenceError
A função run () cria um escopo. A mensagem variável está disponível dentro da função, mas não fora.
Da mesma forma, a função cria escopo para variáveis declaradas com const e let, e até mesmo para outras funções e expressões de função:
function run() {
// run()
const two = 2
let one = 1
function run2() {}
var run3 = () => {}
console.log(two)
console.log(one)
console.log(run2)
console.log(run3)
}
run() // 2 1 ƒ run2() {} () => {}
console.log(two) // ReferenceError
console.log(one) // ReferenceError
console.log(run2) // ReferenceError
console.log(run3) // ReferenceError
4. Visibilidade do módulo
Os módulos ES6 também criam escopo para variáveis, funções e classes.
O módulo de círculo cria um pi constante (para uso interno):
// circle
const pi = 3.14
console.log(pi) // 3.14
// pi
A variável pi é declarada dentro do módulo circle e não é exportada de lá.
Em seguida, o módulo de círculo é importado:
import './circle'
console.log(pi) // ReferenceError
A variável pi não está disponível fora do módulo de círculo (até que seja exportada usando export).
O escopo modular encapsula módulos. Isso significa que variáveis privadas (que não são exportadas) são usadas para as próprias necessidades do módulo e são protegidas contra acesso externo.
Assim, podemos dizer que o escopo é um mecanismo de encapsulamento de blocos de código, funções e módulos.
5. Os escopos podem ser aninhados
Um recurso interessante dos escopos é que eles podem ser aninhados uns nos outros.
No exemplo a seguir, a função run () cria um escopo e, dentro dele, um bloco if cria outro escopo:
function run() {
// run()
const message = ', , !'
if (true) {
// if
const friend = ''
console.log(message) // ', , !'
}
console.log(friend) // ReferenceError
}
run()
O escopo do bloco if está aninhado no escopo da função run ().
Um escopo que está dentro de outro escopo é chamado de escopo interno. No exemplo acima, este é o escopo do bloco if.
Um escopo que contém outro escopo é chamado de escopo externo. No exemplo acima, este é o escopo da função run ().
E quanto à disponibilidade variável? Uma regra simples para lembrar é:
Variáveis do escopo externo estão disponíveis no escopo interno.
Portanto, a variável de mensagem está disponível dentro do bloco if.
6. Escopo global
O escopo global é o escopo mais externo. Ele está disponível para qualquer escopo interno ou local. No navegador, o escopo global é criado quando o arquivo JavaScript especificado no atributo src da tag de script é carregado:
<script src="script.js">
// script.js
// escopo global
let counter = 1
Variáveis declaradas no escopo global são variáveis globais. Eles estão disponíveis em qualquer outra área.
O escopo global é um mecanismo que permite que o tempo de execução do JavaScript (navegador, Node.js) exponha objetos de host (ou seja, de propriedade do ambiente) para aplicativos como variáveis globais.
Por exemplo, janela e documento são variáveis globais (objetos) fornecidos pelo navegador. No Node.js, essa variável é, por exemplo, o objeto do processo.
7. Âmbito lexical
Vamos definir duas funções, uma das quais aninhada na outra:
function outer() {
// outer()
let v = ' outer()!'
function inner() {
// inner()
console.log(v) // ' outer()!'
}
return inner
}
const f = outer()
f()
Dê uma olhada na última linha: inner () é chamado fora do escopo de outer (). Como o JavaScript sabe que o valor impresso no console na função inner () pertence à variável v declarada na função outer ()?
Resposta: graças ao escopo léxico.
JavaScript implementa um mecanismo chamado escopo léxico ou estático. O escopo lexical significa que a acessibilidade das variáveis é determinada estaticamente pela posição dessas variáveis dentro do escopo da função aninhada: as variáveis do escopo da função externa estão disponíveis no escopo da função aninhada.
A definição formal de escopo lexical é a seguinte:
O escopo léxico consiste em escopos externos estaticamente definidos, ou seja, de regiões externas, corrigido pelo uso de variáveis dessas regiões em funções internas.
No exemplo acima, o escopo léxico da função inner () consiste no escopo da função outer ().
Além disso, inner () é um encerramento porque usa o valor da variável do escopo lexical.
8. Isolamento de variáveis
Obviamente, o escopo isola as variáveis. Isso permite que diferentes escopos contenham variáveis com o mesmo nome.
Você pode usar variáveis de contagem, índice, corrente, valor, etc. em diferentes áreas sem a ameaça de colisões (conflitos de nomes).
Por exemplo:
function foo() {
// foo()
let count = 1
console.log(count) // 1
}
function bar() {
// bar()
let count = 2
console.log(count) // 2
}
foo()
bar()
Conclusão
O escopo determina a disponibilidade de variáveis. Uma variável declarada no escopo atual está disponível apenas dentro dele.
Em JavaScript, os escopos são criados por blocos, funções e módulos.
As variáveis declaradas com as palavras-chave const e let podem ser em bloco, funcionais ou modulares, enquanto as variáveis declaradas com a palavra-chave var não têm escopo em bloco.
Os escopos podem ser aninhados. Variáveis declaradas no escopo externo estão disponíveis no escopo interno.
O escopo léxico consiste em escopos externos definidos estaticamente. Qualquer função, independentemente de onde seja executada, tem acesso às variáveis de seu escopo lexical (esta é a essência dos encerramentos).
Espero que o artigo tenha sido útil para você. Obrigado pela atenção.