Neste artigo, você aprenderá sobre o escopo e como ele funciona no JavaScript.
Escopo é um conceito fundamental em JavaScript e outras linguagens de programação que define o contexto em que as variáveis são acessadas e usadas. Ele se torna mais útil e aplicável ao seu código à medida que você continua aprendendo sobre JavaScript e trabalhando mais com variáveis.
O escopo pode ajudar você a:
- Usar a memória com mais eficiência:o escopo permite carregar variáveis somente quando necessário. Se uma variável estiver fora do escopo, não é necessário disponibilizá-la para o código que está sendo executado no momento.
- Encontre e corrija bugs com mais facilidade:isolar variáveis com escopo local facilita a solução de bugs no seu código porque, ao contrário das variáveis globais, você pode confiar que o código de um escopo externo não pode manipular variáveis com escopo local.
- Crie pequenos blocos de código reutilizáveis:por exemplo, você pode escrever uma função pura que não dependa do escopo externo. É possível mover essa função facilmente para outro lugar com mudanças mínimas.
O que é escopo?
O escopo de uma variável determina de onde dentro do código você pode usá-la.
O JavaScript define variáveis de escopo global ou local:
- As variáveis com escopo global estão disponíveis em todos os outros escopos no código JavaScript.
- Variáveis com escopo local estão disponíveis apenas em um contexto local específico e são criadas por palavras-chave, como
var
,let
econst
. Se você usar as palavras-chavevar
,let
ouconst
para criar uma variável em uma função, ela terá escopo local.
As próximas seções deste artigo discutem o bloco e o escopo lexical:
- As variáveis de escopo de bloco estão disponíveis localmente para um bloco, conforme determinado pelo local das chaves em que a instrução de bloco é definida. Somente as variáveis declaradas com as palavras-chave
let
ouconst
têm escopo de bloqueio. - O escopo léxico usa o local em que uma variável é declarada no código-fonte para determinar onde ela está disponível. Use fechamentos para conceder a uma função incluída acesso às variáveis referenciadas no escopo externo conhecido como ambiente lexical.
Quando uma variável é acessada no escopo, o JavaScript retorna o valor atribuído ou produz um erro.
Para declarar uma variável:
- Use as palavras-chave
var
,const
oulet
para declarar variáveis de escopo local ou global. - Use as palavras-chave
const
oulet
para declarar variáveis de escopo de bloco.
Quando você declara uma variável var
em uma função, a declaração disponibiliza a variável para a função de inclusão mais próxima. Não é possível usar a palavra-chave var
para declarar variáveis com escopo de bloco.
Exemplos de escopo
Este exemplo demonstra o escopo global porque a variável greeting
é declarada fora de qualquer função ou bloco, o que disponibiliza o valor para todo o código no documento atual:
const greeting = 'hello';
console.log(greeting); // 'hello'
No exemplo de escopo global, a variável greeting
recebe um valor hello
.
Este exemplo demonstra o escopo local porque declara a variável greeting
com a palavra-chave let
em uma função. A variável greeting
tem escopo local e não está disponível fora da função.
function greet() {
let greeting = 'Hello World!';
console.log(greeting);
}
Este exemplo demonstra o escopo do bloco porque declara a variável greeting
dentro de um bloco para que ela só possa ser acessada dentro das chaves:
if (true) {
const greeting = 'hello';
}
console.log(greeting); // ReferenceError: greeting is not defined
Quando a função console.log
tenta gerar o valor da variável greeting
, o JavaScript retorna uma mensagem de erro ReferenceError
em vez da mensagem hello
esperada. Por quê?
Um erro é retornado porque a variável greeting
tem o escopo do bloco, e o bloco mais próximo faz parte da instrução condicional if
. Não é possível acessar as variáveis let
e const
declaradas dentro de um bloco de fora dele. Portanto, só é possível acessar a variável greeting
entre chaves, que especifica o escopo do bloco.
Este exemplo corrige o erro porque move o método console.log(message)
dentro das chaves. O código atualizado realoca o método console.log(message)
dentro do bloco.
if (true) {
const greeting = 'hello';
console.log(greeting);
}
Tipos de escopo
Escopo global
É possível acessar variáveis com escopo global de qualquer lugar no programa.
Considere um arquivo HTML que importa dois arquivos JavaScript: file-1.js
e file-2.js
:
<script src="file-1.js"></script>
<script src="file-2.js"></script>
Neste exemplo, a variável globalMessage
tem um escopo global e é escrita fora de uma função. Durante a execução e a execução, é possível acessar o valor da variável globalMessage
em qualquer lugar no programa JavaScript.
É possível ver o conteúdo dos arquivos file-1.js
e file-2.js
neste snippet de código. Observe a disponibilidade da variável globalMessage
nos dois arquivos.
// file-1.js
function hello() {
var localMessage = 'Hello!';
}
var globalMessage = 'Hey there!';
// file-2.js
console.log(localMessage); // localMessage is not defined
console.log(globalMessage); // Hey there!
Há outro tipo de escopo que não é muito discutido neste artigo. Se você criar uma variável dentro de um módulo JavaScript, mas fora de uma função ou bloco, ela não terá escopo global, e sim escopo do módulo. As variáveis com escopo de módulo estão disponíveis em qualquer parte do módulo atual, mas não em outros arquivos ou módulos. Para disponibilizar uma variável com escopo de módulo para outros arquivos, é preciso exportá-la do módulo em que ela foi criada e, em seguida, import do módulo que precisa acessar a variável.
Escopo local e escopo da função
Quando você cria variáveis em uma função JavaScript com as palavras-chave var
, let
ou const
, elas são locais para a função, então só podem ser acessadas de dentro da função. As variáveis locais são criadas quando uma função é iniciada e são excluídas quando a execução da função termina.
Este exemplo declara a variável total
na função addNumbers()
. Você só pode acessar as variáveis a
, b,
e total
na função addNumbers()
.
function addNumbers(a, b) {
const total = a + b;
}
addNumbers(3, 4);
É possível usar as palavras-chave let
e const
para nomear variáveis. Quando você usa a palavra-chave let
, o JavaScript pode atualizar a variável. No entanto, com a palavra-chave const
, a variável permanece constante.
var variable1 = 'Declared with var';
var variable1 = 'Redeclared with var';
variable1; // Redeclared with var
let variable2 = 'Declared with let. Cannot be redeclared.';
variable2 = 'let cannot be redeclared, but can be updated';
variable2; // let cannot be redeclared, but can be updated
const variable3 = 'Declared with const. Cannot be redeclared or updated';
variable3; // Declared with const. Cannot be redeclared or updated
Escopo do bloqueio
Blocos são usados para agrupar uma única instrução ou um conjunto de instruções. Você pode usar as palavras-chave const
ou let
para declarar uma variável local com escopo de bloco. Não é possível usar a palavra-chave var
para declarar variáveis com escopo de bloqueio.
Por exemplo, neste bloco, o escopo da variável name
e o valor "Elizabeth"
estão dentro das chaves. As variáveis em um escopo de bloco não estão disponíveis fora do bloco.
{
const name = "Elizabeth";
}
É possível usar variáveis com escopo de bloco nas instruções if
, for
ou while
.
Observe as duas repetições for
neste snippet de código. Uma repetição for
usa a palavra-chave var
para declarar a variável do inicializador, que aumenta com os números 0
, 1
e 2
. A outra repetição for
usa a palavra-chave let
para declarar a variável de inicializador.
for (var i = 0; i < 2; i++) {
// ...
}
console.log(i); // 2
for (let j = 0; j < 2; j++) {
// ...
}
console.log(j); // The j variable isn't defined.
No exemplo de código anterior, a variável i
na primeira repetição for
vazou para fora da repetição for
e ainda mantém um valor 2
porque a palavra-chave var
não usa o escopo do bloco. O problema foi corrigido na segunda repetição for
, em que a variável j
declarada com a palavra-chave let
tem o escopo definido para o bloco da repetição for
e não existe depois que a repetição for
é concluída.
Reutilizar o nome de uma variável em um escopo diferente
O escopo pode isolar uma variável dentro de uma função, mesmo quando você reutiliza o mesmo nome de variável em outro lugar em um escopo diferente.
Este exemplo mostra como usar o escopo permite reutilizar o mesmo nome de variável em funções diferentes:
function listOne() {
let listItems = 10;
console.log(listItems); // 10
}
function listTwo() {
let listItems = 20;
console.log(listItems); // 20
}
listOne();
listTwo();
As variáveis listItems
nas funções listOne()
e listTwo()
recebem os valores esperados e, portanto, não entram em conflito.
Fechamentos e escopo léxico
Encerramentos se referem a uma função fechada em que uma função interna pode acessar o escopo externo, também conhecido como ambiente lexical. Assim, em JavaScript, você usa fechamentos para permitir que as funções façam referência ao ambiente lexico externo, o que permite que o código dentro de uma função referencie variáveis declaradas fora dela. Na verdade, é possível codificar uma cadeia de referências a ambientes léxicos externos para que uma função seja chamada por outra que, por sua vez, seja chamada por outra função.
Neste exemplo, o código forma uma interdição com o ambiente léxico criado quando a função outer()
é invocada, que se fecha sobre a variável hello
. Assim, a variável hello
é usada na função de callback setTimeout
.
function outer() {
const hello = 'world';
setTimeout(function () {
console.log('Within the closure!', hello)
}, 100);
}
outer();
Com escopo lexical, o escopo é determinado durante a compilação do código-fonte, não no momento da execução. Para saber mais sobre o ambiente léxico, consulte Escopo lexical e fechamento.
Módulos
Os módulos JavaScript ajudam a organizar o código JavaScript. Usados corretamente, eles fornecem uma estrutura eficaz para a base de código e ajudam na reutilização do código. Em vez de usar variáveis globais para compartilhar variáveis em arquivos diferentes, os módulos JavaScript oferecem uma técnica para exportar e import variáveis.
// hello.js file
function hello() {
return 'Hello world!';
}
export { hello };
// app.js file
import { hello } from './hello.js';
console.log(hello()); // Hello world!
Demonstração do visualizador de escopo
O escopo é um conceito fundamental que todo desenvolvedor de JavaScript deve entender. Para entender melhor o sistema de escopo, tente escrever seu próprio código com o JS Scope Visualizer (Visualizador de escopo JS). A demonstração usa cores no código para ajudar a visualizar escopos JavaScript.
Conclusão
Este artigo apresenta diferentes tipos de escopo. O escopo do JavaScript é um dos conceitos mais avançados no desenvolvimento da Web, então é ótimo que você tenha lido esse conteúdo e tendo dedicado tempo para entender esse assunto.
O escopo não é um recurso voltado para o usuário. Ela afeta apenas o desenvolvedor da Web que escreve o código, mas o conhecimento de como o escopo funciona pode ajudar você a corrigir bugs quando eles surgirem.