Escopo de Variáveis - JavaScript

Todas as variáveis e constantes em JavaScript têm um escopo definido dentro do qual elas podem operar.

Variáveis globais

Todas as variáveis e constantes que são declaradas fora das funções são globais:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>Programício</title>
</head>
<body>
<script>
var x = 5;
let y = 8;
const z = 9;

function displaySum() {
    var sum = x + y + z;
    console.log(sum);
}
displaySum(); // 22
</script>
</body>
</html>

Aqui, as variáveis x e y e a constante z são globais. Elas estão acessíveis de qualquer lugar do programa.

No entanto, a variável sum não é global, pois é definida dentro de uma função e visível apenas nessa função.

Definindo o escopo local

Para definir um escopo local em JavaScript, usa-se chaves { }, que criam um bloco de código. Esse bloco de código pode ser anônimo, pode ser nomeado, por exemplo, uma função, ou pode representar uma construção condicional ou cíclica. Por exemplo, a definição de variáveis em um bloco de código anônimo:

{
    var x = 5;
    let y = 8;
    const z = 9;
}

No entanto, nesse caso, o comportamento da variável depende de como ela é definida (através de var ou let) e do tipo de bloco. var define variáveis locais de nível de função, enquanto let define variáveis locais de nível de bloco de código (de maneira semelhante, const define constantes de nível de bloco de código). Vamos considerar a diferença.

Variáveis e constantes de função

Variáveis e constantes definidas dentro de uma função são visíveis (ou seja, podem ser usadas) apenas dentro dessa função:

function print() {
    var x = 5;
    let y = 8;
    const z = 9;
    console.log("Function print: x =", x);
    console.log("Function print: y =", y);
    console.log("Function print: z =", z);
}
print();
console.log("Global: x =", x);  // Uncaught ReferenceError: x is not defined

As variáveis x e y e a constante z são locais, existem apenas dentro dos limites da função. Fora da função, elas não podem ser usadas, por isso obtemos a seguinte saída no console:

Function print: x = 5
Function print: y = 8
Function print: z = 9
Uncaught ReferenceError: x is not defined

Aqui vemos que ao tentar acessar a variável x fora da função print(), o navegador exibe um erro. Este comportamento é independente de ser uma variável var, let ou const. O comportamento é o mesmo para todas as variáveis e constantes.

Variáveis locais em blocos de código, condições e laços

Com variáveis definidas em blocos de código anônimos, bem como em laços e construções condicionais, a situação é um pouco mais complicada.

Variável var

Uma variável declarada com var pode ser usada fora do bloco:

// bloco anônimo
  {
      var a = 5;
  }
  console.log("a =", a);  // a = 5
   
  // construção condicional
  if(true) {
      var b = 6;
  }
  console.log("b =", b);  // b = 6
   
  // laço
  for(let i = 0; i < 5; i++) { 
      var c = 7;
  }
  console.log("c =", c);  // c = 7

A única condição é que o bloco de código deve ser executado para inicializar a variável. Assim, no exemplo acima, a condição na construção if e no laço for é tal que o bloco dessas construções será executado. No entanto, e se a condição for diferente e o bloco não for executado?

if(false) {
    var b = 6;
}
console.log("b =", b);  // b = undefined
 
// laço
for(let i = 1; i < 0; i++) {
    var c = 7;
}
console.log("c =", c);  // c = undefined

Neste caso, ainda podemos acessar as variáveis, mas elas terão o valor undefined.

Variável let e Constantes

Agora vejamos como se comportam as variáveis declaradas com a palavra-chave let em uma situação semelhante:

{
  let a = 5;
}
console.log("a =", a); // Uncaught ReferenceError: a is not defined

Neste caso, receberemos um erro. Só podemos usar variáveis let declaradas dentro de um bloco de código, apenas dentro desse bloco de código.

O mesmo se aplica às constantes:

{
const b = 5;
}
console.log("b =", b); // Uncaught ReferenceError: b is not defined

Escopo de variáveis

E se tivermos duas variáveis - uma global e outra local - com o mesmo nome?

var z = 89;

function print() {
  var z = 10;
  console.log(z); // 10
}
print(); // 10

Neste caso, a função usará a variável z definida na própria função, ou seja, a variável local ocultará a variável global. No entanto, o comportamento específico depende de como a variável é declarada.

Ocultando a Variável var

Foi mencionado anteriormente que var declara uma variável no nível da função. Portanto, não podemos definir duas variáveis com o mesmo nome em uma função e em um bloco de código dessa função ao mesmo tempo. Se fizermos isso, ao declarar a variável no nível do bloco, estamos mudando o valor da variável de nível de função:

function displayZ() { 
    var z = 20;
 
    {
        var z = 30; // Não define uma nova variável, mas altera o valor da variável z no nível da função
        console.log("Bloco:", z);
    }
    console.log("Função:", z);
}
displayZ();

Aqui, a declaração da variável z dentro do bloco é equivalente a mudar o valor da variável de nível de função. A mesma variável é referenciada em ambos os casos. A saída do console:

Bloco: 30
Função: 30

Ocultando a Variável let

Como mencionado anteriormente, a palavra-chave let declara uma variável no nível do bloco de código. Ou seja, cada bloco de código define um novo escopo onde a variável existe. Fora do bloco, onde a variável foi declarada, ela não existe. Portanto, podemos definir uma variável tanto no nível do bloco quanto no nível da função ao mesmo tempo (ao contrário de var):

let z = 10;
function displayZ() {
  
    let z = 20;
      
    {
        let z = 30;
        console.log("Block:", z);
    }
      
    console.log("Function:", z);
}
  
displayZ();
console.log("Global:", z);

Aqui, dentro da função displayZ, há um bloco de código no qual uma variável z é declarada. Ela oculta a variável global e a variável z declarada no nível da função.

E neste caso, obtemos a seguinte saída do console:

Bloco: 30
Função: 20
Global: 10

Constantes

Tudo o que foi dito sobre a palavra-chave let aplica-se também à palavra-chave const, que declara constantes no nível do bloco de código. Blocos de código definem o escopo das constantes, e constantes definidas em blocos de código aninhados ocultam as externas com o mesmo nome:

const z = 10;
function displayZ() {
    const z = 20;
      
    {
        const z = 30;
        console.log("Block:", z);   // 30
    }
    console.log("Function:", z);    // 20
}
  
displayZ();
console.log("Global:", z);  // 10

Cadeia de Escopo / Scope Chain

Ao executar o código, quando o interpretador encontra algum identificador (nome de uma variável, constante ou função), ele inicialmente procura a definição desse identificador no escopo atual. Isso permite o funcionamento correto do escopo de variáveis e constantes. Por exemplo:

const z = 10;
function displayZ() {
    const z = 20;
    console.log(z); // 20
}

displayZ();     // 20

Aqui, o interpretador vê que dentro da função displayZ há uma referência ao identificador z, e procura a definição desse identificador dentro da função. Como há uma constante const z = 20 na função, essa constante é usada.

Outro exemplo:

const z = 10;
function displayZ() {
    console.log(z); // 10
}

displayZ();     // 10

Como a função displayZ não tem uma definição para o identificador z, o interpretador recorre à cadeia de escopo, procurando no escopo circundante e assim sucessivamente até o escopo global.

Variáveis não Declaradas

Em JavaScript, é possível declarar variáveis sem usar as palavras-chave let ou var. Por exemplo:

<!DOCTYPE html>
  <html>
  <head>
      <meta charset="utf-8" />
      <title>Programício</title>
  </head>
  <body>
  <script>
      {
          username = "Tom"; 
      }
          console.log(username);  // não há erro

      {
          console.log(username);  // não há erro, está disponível dentro de outros blocos de código
      }
  </script>
  </body>
  </html>

Se não usarmos as palavras-chave let ou var ao definir uma variável dentro de uma função, ela será global. Por exemplo:

function setAge() {
  userage = 39;
}

setAge();
console.log(userage);   // 39

Mesmo que a variável userage não seja definida fora da função setAge, ela está disponível no contexto externo. O único requisito é chamar a função onde essa variável foi definida.

No entanto, se a função não for chamada, a variável não será definida:

function setAge() {
  userage = 39;
}

// setAge();    // Função NÃO chamada
console.log(userage);   // erro - Uncaught ReferenceError: userage is not defined

Teríamos o mesmo erro se não apenas atribuíssemos um valor à variável, mas também a definíssemos como local em relação à função:

function setAge() {
  var userage = 39;
}

setAge();
console.log(userage);   // erro - Uncaught ReferenceError: userage is not defined

Strict Mode

Declarar variáveis globais em funções pode levar a erros potenciais. Para evitá-los, usamos o strict mode (modo restrito). Ele pode ser ativado de duas maneiras:

  1. Adicionando a expressão "use strict" no início do código JavaScript, aplicando o strict mode a todo o código.

  2. Adicionando a expressão "use strict" no início do corpo da função, aplicando o strict mode apenas a essa função.

Aplicando o strict mode globalmente:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>Programício</title>
</head>
<body>
<script>
    "use strict";       // modo restrito ativado
    username = "Tom";   // Uncaught ReferenceError: username is not defined
    console.log(username);
</script>
</body>
</html>

Aqui, obtemos um erro SyntaxError: Unexpected identifier, indicando que a variável username não foi definida.

Obtemos um erro semelhante ao declarar uma variável global dentro de uma função:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>Programício</title>
</head>
<body>
<script>
    "use strict";       // modo restrito ativado
    function setAge() {
        userage = 39;       // Uncaught ReferenceError: userage is not defined
    }

    setAge();
    console.log(userage);
</script>
</body>
</html>

Aplicando o strict mode em uma função:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>Programício</title>
</head>
<body>
<script>
    username = "Tom";   // ok
    console.log(username);  // Tom

    function setAge() {
        "use strict";       // modo restrito ativado na função
        userage = 39;       // Uncaught ReferenceError: userage is not defined
    }

    setAge();
    console.log(userage);
</script>
</body>
</html>
Política de Privacidade

Copyright © www.programicio.com Todos os direitos reservados

É proibida a reprodução do conteúdo desta página sem autorização prévia do autor.

Contato: programicio@gmail.com