Variáveis

As variáveis são uma estrutura de dados que atribui um nome representativo a um valor. Eles podem conter dados de qualquer tipo.

O nome de uma variável é chamado de identificador. Um identificador válido precisa seguir estas regras:

  • Os identificadores podem conter letras Unicode, cifrões ($), sublinhados (_), dígitos (0-9) e até mesmo alguns caracteres Unicode.
  • Os identificadores não podem conter espaços em branco, porque o analisador usa espaços em branco para separar elementos de entrada. Por exemplo, se você tentar chamar uma variável my Variable em vez de myVariable, o analisador vai encontrar dois identificadores, my e Variable, e gerar um erro de sintaxe ("token inesperado: identificador").
  • Os identificadores precisam começar com uma letra, sublinhado (_) ou cifrão ($). Eles não podem começar com dígitos para evitar confusão entre números e identificadores:

    let 1a = true;
    
    > Uncaught SyntaxError: Invalid or unexpected token
    

    Se o JavaScript permitisse números no início de um identificador, isso permitiria identificadores compostos apenas por números, causando conflitos entre números usados como números e números usados como identificadores:

    let 10 = 20
    
    10 + 5
    > ?
    
  • Palavras reservadas que já têm significado sintático não podem ser usadas como identificadores.

  • Os identificadores não podem conter caracteres especiais (! . , / \ + - * =).

As regras a seguir não são rígidas para a criação de identificadores, mas são práticas recomendadas do setor que facilitam a manutenção do código. Se o projeto específico tiver padrões diferentes, siga esses padrões para manter a consistência.

Seguindo o exemplo definido pelos métodos e propriedades integrados do JavaScript, o formato came case (também estilizado como "camelCase") é uma convenção muito comum para identificadores compostos por várias palavras. A concatenação é a prática de colocar em maiúscula a primeira letra de cada palavra, exceto a primeira, para melhorar a legibilidade sem espaços.

let camelCasedIdentifier = true;

Alguns projetos usam outras convenções de nomenclatura, dependendo do contexto e da natureza dos dados. Por exemplo, a primeira letra de uma classe normalmente é maiúscula, então os nomes de classes com várias palavras geralmente usam uma variante de letras maiúsculas concatenadas, comumente chamada de "letras maiúsculas concatenadas" ou Pascal.

class MyClass {

}

Os identificadores precisam descrever de forma concisa a natureza dos dados que contêm (por exemplo, currentMonthDays é um nome melhor do que theNumberOfDaysInTheCurrentMonth) e ser lidos claramente de relance (originalValue é melhor do que val). Os identificadores myVariable usados neste módulo funcionam no contexto de exemplos isolados, mas não seriam úteis no código de produção porque não fornecem informações sobre quais dados eles contêm.

Os identificadores não podem ser muito específicos sobre os dados que contêm, porque os valores podem mudar dependendo de como os scripts agem nesses dados ou das decisões tomadas pelos mantenedores no futuro. Por exemplo, uma variável que recebeu originalmente o identificador miles pode precisar ser alterada para um valor em quilômetros mais tarde no projeto, exigindo que os mantenedores mudem todas as referências a essa variável para evitar confusão no futuro. Para evitar isso, use distance como seu identificador.

O JavaScript não dá nenhum privilégio ou significado especial a identificadores que começam com caracteres de sublinhado (_), mas eles geralmente são usados para mostrar que uma variável, um método ou uma propriedade é "privada", o que significa que ela é destinada apenas ao uso no contexto do objeto que a contém e não pode ser acessada ou modificada fora desse contexto. Essa é uma convenção transferida de outras linguagens de programação e antecede a adição das propriedades privadas do JavaScript.

Declaração de variável

Há várias maneiras de informar o JavaScript sobre um identificador, um processo chamado de "declaração" de uma variável. Uma variável é declarada usando as palavras-chave let, const ou var.

let myVariable;

Use let ou var para declarar uma variável que pode ser mudada a qualquer momento. Essas palavras-chave informam ao interpretador JavaScript que uma string de caracteres é um identificador que pode conter um valor.

Ao trabalhar em uma base de código moderna, use let em vez de var. var ainda funciona em navegadores modernos, mas tem alguns comportamentos não intuitivos que foram definidos nas versões mais antigas do JavaScript e não puderam ser alterados mais tarde para preservar a compatibilidade com versões anteriores. let foi adicionado no ES6 para resolver alguns problemas com o design de var.

Uma variável declarada é inicializada atribuindo um valor a ela. Use um sinal de igual (=) para atribuir ou reatribuir um valor a uma variável. Você pode fazer isso como parte da mesma instrução que a declara:

let myVariable = 5;

myVariable + myVariable
> 10

Também é possível declarar uma variável com let (ou var) sem inicializá-la imediatamente. Se você fizer isso, o valor inicial da variável será undefined até que o código atribua um valor a ela.

let myVariable;

myVariable;
> undefined

myVariable = 5;

myVariable + myVariable
> 10

Uma variável com um valor undefined é diferente de uma variável indefinida cujo identificador ainda não foi declarado. Fazer referência a uma variável que você não declarou causa um erro.

myVariable
> Uncaught ReferenceError: myVariable is not defined

let myVariable;

myVariable
> undefined

A associação de um identificador a um valor geralmente é chamada de "vinculação". A sintaxe que segue as palavras-chave let, var ou const é chamada de "lista de vinculação" e permite várias declarações de variáveis separadas por vírgulas (que terminam com o ponto e vírgula esperado). Isso torna os seguintes snippets de código funcionalmente idênticos:

let firstVariable,
     secondVariable,
     thirdVariable;
let firstVariable;
let secondVariable;
let thirdVariable;

Reatribuir o valor de uma variável não usa let (ou var), porque o JavaScript já sabe que a variável existe:

let myVariable = true;

myVariable
> true

myVariable = false;

myVariable
> false

É possível reatribuir novos valores às variáveis com base nos valores atuais:

let myVariable = 10;

myVariable
> 10

myVariable = myVariable * myVariable;

myVariable
> 100

Se você tentar declarar novamente uma variável usando let em um ambiente de produção, vai receber um erro de sintaxe:

let myVariable = true;
let myVariable = false;
> Uncaught SyntaxError: redeclaration of let myVariable

As ferramentas para desenvolvedores dos navegadores são mais permissivas em relação à rededicação de let (e class). Portanto, talvez você não encontre o mesmo erro no console do desenvolvedor.

Para preservar a compatibilidade com navegadores legados, o var permite a redefinição desnecessária sem erros em qualquer contexto:

var myVariable = true;
var myVariable = false;

myVariable\
> false

const

Use a palavra-chave const para declarar uma constante, um tipo de variável que precisa ser inicializada imediatamente e que não pode ser modificada. Os identificadores de constantes seguem todas as mesmas regras das variáveis declaradas usando let (e var):

const myConstant = true;

myConstant
> true

Não é possível declarar uma constante sem atribuir imediatamente um valor a ela, porque as constantes não podem ser reatribuídas depois de criadas. Portanto, qualquer constante não inicializada ficará undefined para sempre. Se você tentar declarar uma constante sem inicializá-la, vai receber um erro de sintaxe:

const myConstant;
Uncaught SyntaxError: missing = in const declaration

Tentar mudar o valor de uma variável declarada com const da mesma forma que você mudaria o valor de uma variável declarada com let (ou var) causa um erro de tipo:

const myConstant = true;

myConstant = false;
> Uncaught TypeError: invalid assignment to const 'myConstant'

No entanto, quando uma constante é associada a um objeto, as propriedades desse objeto podem ser alteradas.

const constantObject = { "firstvalue" : true };

constantObject
> Object { firstvalue: true }

constantObject.secondvalue = false;

constantObject
> Object { firstvalue: true, secondvalue: false }

Uma constante que contém um objeto é uma referência imutável a um valor de dados mutável. Embora a constante não possa ser alterada, as propriedades do objeto referenciado podem ser alteradas, adicionadas ou removidas:

const constantObject = { "firstvalue" : true };

constantObject = false
> Uncaught TypeError: invalid assignment to const 'constantObject'

Quando você não espera que uma variável seja reatribuída, é recomendável torná-la uma constante. O uso de const informa à equipe de desenvolvimento ou aos futuros mantenedores de um projeto que não é necessário mudar esse valor para evitar a quebra das suposições feitas pelo código sobre como ele é usado. Por exemplo, que uma variável será avaliada em relação a um tipo de dados esperado.

Escopo de variáveis

O escopo de uma variável é a parte de um script em que ela está disponível. Fora do escopo de uma variável, ela não será definida, não como um identificador que contém um valor undefined, mas como se não tivesse sido declarada.

Dependendo da palavra-chave usada para declarar uma variável e do contexto em que ela é definida, é possível definir o escopo das variáveis para instruções de bloco (escopo de bloco), funções individuais (escopo de função) ou todo o aplicativo JavaScript (escopo global).

Escopo do bloco

Qualquer variável declarada usando let ou const tem escopo para a instrução de bloco mais próxima que a contém, o que significa que a variável só pode ser acessada dentro desse bloco. Tentar acessar uma variável com escopo de bloco fora do bloco que a contém causa o mesmo erro que tentar acessar uma variável que não existe:

{
    let scopedVariable = true;
    console.log( scopedVariable );
}
> true

scopedVariable
> ReferenceError: scopedVariable is not defined

No JavaScript, uma variável com escopo de bloco não existe fora do bloco que a contém. Por exemplo, é possível declarar uma constante dentro de um bloco e, em seguida, declarar outra constante fora desse bloco que usa o mesmo identificador:

{
  const myConstant = false;
}
const myConstant = true;

scopedConstant;
> true

Embora uma variável declarada não possa ser estendida para o bloco pai, ela está disponível para todos os blocos descendentes:

{
    let scopedVariable = true;
    {
    console.log( scopedVariable );
    }
}
> true

O valor de uma variável declarada pode ser alterado em um bloco descendente:

{
    let scopedVariable = false;
    {
    scopedVariable = true;
    }
    console.log( scopedVariable );
}
> true

Uma nova variável pode ser inicializada com let ou const dentro de um bloco descendente sem erros, mesmo que use o mesmo identificador que uma variável em um bloco pai:

{
    let scopedVariable = false;
    {
    let scopedVariable = true;
    }
    console.log( scopedVariable );
}
> false

Escopo da função

As variáveis declaradas usando var têm escopo para a função que as contém mais de perto (ou o bloco de inicialização estática dentro de uma classe).

function myFunction() {
    var scopedVariable = true;

    return scopedVariable;
}

scopedVariable;
> ReferenceError: scopedVariable is not defined

Isso ainda acontece depois que uma função é chamada. Mesmo que a variável seja inicializada durante a execução da função, ela ainda não estará disponível fora do escopo da função:

function myFunction() {
    var scopedVariable = true;

    return scopedVariable;
}

scopedVariable;
> ReferenceError: scopedVariable is not defined

myFunction();
> true

scopedVariable;
> ReferenceError: scopedVariable is not defined

Escopo global

Uma variável global está disponível em todo um aplicativo JavaScript, dentro de todos os blocos e funções, para qualquer script na página.

Embora isso possa parecer um padrão desejável, variáveis que qualquer parte de um aplicativo pode acessar e modificar podem adicionar sobrecarga desnecessária ou até mesmo causar colisões com variáveis em outro lugar de um aplicativo com o mesmo identificador. Isso se aplica a todos os JavaScripts envolvidos na renderização de uma página, incluindo bibliotecas de terceiros e análises de usuários. Portanto, é recomendado evitar poluir o escopo global sempre que possível.

Qualquer variável declarada usando var fora de uma função pai ou usando let ou const fora de um bloco pai é global:

var functionGlobal = true; // Global
let blockGlobal = true; // Global

{
    console.log( blockGlobal );
    console.log( functionGlobal );
}
> true
> true

(function() {
    console.log( blockGlobal );
    console.log( functionGlobal );
}());
> true
> true

A atribuição de um valor a uma variável sem declará-la explicitamente (ou seja, nunca usando var, let ou const para criá-la) eleva uma variável ao escopo global, mesmo quando inicializada em uma função ou bloco. Uma variável criada usando esse padrão às vezes é chamada de "global implícita".

function myFunction() {
    globalVariable = "global";

    return globalVariable
}

myFunction()\
> "global"

globalVariable\
> "global"

Elevação de variáveis

As declarações de variáveis e funções são elevadas para o topo do escopo, o que significa que o interpretador JavaScript processa qualquer variável declarada em qualquer ponto de um script e a move para a primeira linha do escopo antes de executar o script. Isso significa que uma variável declarada usando var pode ser referenciada antes de ser declarada sem encontrar um erro:

hoistedVariable
> undefined

var hoistedVariable;

Como apenas a declaração de variável é hospedada, e não a inicialização, as variáveis que não foram declaradas explicitamente com var, let ou const não são elevadas:

unhoistedVariable;
> Uncaught ReferenceError: unhoistedVariable is not defined

unhoistedVariable = true;

Como mencionado anteriormente, uma variável declarada, mas não inicializada, é atribuída a um valor de undefined. Esse comportamento também se aplica a declarações de variável elevadas, mas apenas àquelas declaradas usando var.

hoistedVariable
> undefined

var hoistedVariable = 2 + 2;

hoistedVariable\
> 4

Esse comportamento não intuitivo é uma herança das decisões de design feitas nas versões mais antigas do JavaScript e não pode ser alterado sem o risco de quebrar sites existentes.

let e const resolvem esse comportamento gerando um erro quando uma variável é acessada antes de ser criada:

{
    hoistedVariable;

    let hoistedVariable;
}
> Uncaught ReferenceError: can't access lexical declaration 'hoistedVariable' before initialization

Esse erro é diferente do erro "hoistedVariable is not defined" que você pode esperar ao tentar acessar uma variável não declarada. Como o JavaScript elevou a variável, ele sabe que a variável será criada dentro do escopo especificado. No entanto, em vez de disponibilizar essa variável antes da declaração com um valor de undefined, o interpretador gera um erro. As variáveis declaradas com let ou const (ou class) são consideradas existentes em uma "zona morta temporal" ("TDZ", na sigla em inglês) desde o início do bloco de contenção até o ponto no código em que a variável é declarada.

A zona morta temporal torna o comportamento de let mais intuitivo do que var para autores. Ele também é essencial para o design de const. Como as constantes não podem ser alteradas, uma constante elevada para o topo do escopo e que recebe um valor implícito de undefined não pode ser inicializada com um valor significativo.

Teste seu conhecimento

Com que tipos de caracteres é possível iniciar um identificador?

Uma carta
Um dígito
Um sublinhado

Qual é o método preferido de declarar uma variável cujo valor possa ser alterado a qualquer momento?

let
var
const