HOWTO · JavaScript
Variáveis estáticas em JavaScript
Este tutorial apresenta variáveis estáticas em JavaScript.
Nesta página
Em JavaScript, é possível manter um valor entre chamadas usando um campo estático público de classe, uma propriedade de um objeto de função ou uma variável local mantida por um closure. Todos esses padrões preservam o estado, mas diferem quanto a onde ele fica e quem pode acessá-lo. Use um campo de classe para estado compartilhado pela classe, uma propriedade de função para um estado simples e público associado a uma função, ou um closure quando o código chamador precisar usar o valor sem ler ou alterar diretamente a variável que o armazena.
O que significa uma variável estática em JavaScript
Uma variável estática é um estado associado a uma função ou classe, e não a uma chamada específica. JavaScript não tem uma declaração universal de variável estática que sirva para qualquer função. Em vez disso, oferece vários padrões. A palavra-chave static declara um campo ou método de classe na própria classe. Uma propriedade atribuída a uma função também pertence ao objeto de função. Um closure mantém uma variável local acessível a uma função interna depois que a função externa retorna.
Esses conceitos são relacionados, mas os mecanismos não são intercambiáveis em todos os aspectos. Campos de classe e propriedades de função podem ser acessados por meio do objeto de função ou de classe a que pertencem. Um closure pode manter sua variável privada e expor apenas as operações que você escolher.
Use um campo estático de classe para compartilhar estado pela classe
Um campo estático público pertence à classe, então todas as instâncias referenciam o mesmo campo por meio do nome da classe. Ele não é copiado para cada instância. Essa sintaxe exige um ambiente de execução compatível com campos estáticos públicos de classe. Se o seu ambiente não oferecer suporte a essa sintaxe, use abaixo o padrão de propriedade de função ou de closure.
Execute este exemplo:
O código e os rótulos ou saídas exibidos nesta seção permanecem em inglês.
class VisitCounter {
static count = 0;
static recordVisit() {
return ++VisitCounter.count;
}
}
console.log(VisitCounter.recordVisit());
console.log(VisitCounter.recordVisit());
console.log(VisitCounter.count);
1
2
2
As duas chamadas atualizam o mesmo VisitCounter.count. Como o campo é público, o código também pode ler ou atribuir seu valor usando VisitCounter.count; use um campo estático privado (com um nome iniciado por #) quando a própria classe precisar controlar o acesso. Um membro estático é acessado pela classe, e não por uma instância como new VisitCounter().
Atribua uma propriedade a uma função
Funções são objetos, então uma função nomeada pode ter uma propriedade cujo valor persiste entre chamadas. Essa é uma opção simples para um contador ou cache associado a uma função. A propriedade é pública: outro código pode consultar ou alterar nextId.counter, portanto esse padrão não oferece privacidade.
O código e os rótulos ou saídas exibidos nesta seção permanecem em inglês.
function nextId() {
nextId.counter = (nextId.counter ?? 0) + 1;
return nextId.counter;
}
console.log(nextId());
console.log(nextId());
console.log(nextId.counter);
1
2
2
A mesma ideia se aplica a uma função construtora. Uma propriedade como Widget.count pertence à função construtora, enquanto widget.name pertence a uma instância. Cada instância não recebe uma cópia de Widget.count; o código acessa essa propriedade compartilhada por meio de Widget. A propriedade pertence à classe de forma semelhante ao estado compartilhado por uma classe, mas as propriedades de função em JavaScript não oferecem todos os controles de acesso ou garantias de tipo encontrados em alguns sistemas de classes.
Use um closure para manter estado privado
Um closure permite que uma função interna continue usando uma variável local depois que a função externa termina. Uma IIFE (Immediately Invoked Function Expression) cria esse escopo externo imediatamente e retorna uma operação capaz de atualizar o valor mantido. Como a variável não é colocada em um objeto público, código externo não pode lê-la nem atribuir outro valor a ela diretamente.
O código e os rótulos ou saídas exibidos nesta seção permanecem em inglês.
const counter = (function () {
let count = 0;
return function () {
return ++count;
};
})();
console.log(counter());
console.log(counter());
1
2
Neste exemplo, counter mantém uma referência a count; cada chamada a counter() incrementa esse mesmo valor preservado, então as chamadas exibem 1 e, em seguida, 2. O valor é privado, enquanto counter é a interface pública. Para criar um estado independente, chame uma função de fábrica separada que crie e retorne um novo closure; chamar esse counter retornado apenas incrementa o estado que ele já mantém. Se o código chamador precisar zerar ou consultar a contagem, retorne um pequeno objeto com métodos explícitos, em vez de expor a própria variável.
Por que evitar arguments.callee
arguments.callee referencia a função em execução por meio de seu objeto de argumentos. Padrões antigos usavam esse recurso para atribuir uma propriedade à função, de forma semelhante a uma propriedade de função nomeada. É uma técnica legada e proibida no modo estrito, então o código que a usa pode falhar quando esse modo se aplica, inclusive em módulos ECMAScript. Funções nomeadas deixam essa relação mais clara, e closures permitem manter estado privado sem depender dessa propriedade restrita. Prefira um dos padrões compatíveis apresentados acima em vez de criar código novo com base em arguments.callee.