Variáveis ​​estáticas em JavaScript

716

Como posso criar variáveis ​​estáticas em Javascript?

Rajat
fonte
podemos definir o rótulo ou outra tag html com o atributo de estilo "dispaly: none" e definir o valor da variável para esse valor e a operação nesse valor. Não vamos nos esforçar.
28519 asghar
A solução mais simples que encontrei: não defina uma variável estática na classe. Quando você quiser usar uma variável estática, apenas defina-a ali e então, por exemplo someFunc = () => { MyClass.myStaticVariable = 1; }. Em seguida, basta criar um método estático para retornar o membro estático, por exemplo static getStatic() { return MyClass.myStaticVariable; }. Então você pode simplesmente ligar MyClass.getStatic()de fora da classe para se apossar dos dados estáticos!
Pixel

Respostas:

863

Se você vem de uma linguagem orientada a objeto com base em classe e estaticamente tipada (como Java, C ++ ou C #) , presumo que você esteja tentando criar uma variável ou método associado a um "tipo", mas não a uma instância.

Um exemplo usando uma abordagem "clássica", com funções de construtor, talvez possa ajudá-lo a entender os conceitos básicos do JavaScript OO:

function MyClass () { // constructor function
  var privateVariable = "foo";  // Private variable 

  this.publicVariable = "bar";  // Public variable 

  this.privilegedMethod = function () {  // Public Method
    alert(privateVariable);
  };
}

// Instance method will be available to all instances but only load once in memory 
MyClass.prototype.publicMethod = function () {    
  alert(this.publicVariable);
};

// Static variable shared by all instances
MyClass.staticProperty = "baz";

var myInstance = new MyClass();

staticPropertyé definido no objeto MyClass (que é uma função) e não tem nada a ver com suas instâncias criadas, o JavaScript trata as funções como objetos de primeira classe ; portanto, sendo um objeto, você pode atribuir propriedades a uma função.

ATUALIZAÇÃO: O ES6 introduziu a capacidade de declarar classes por meio da classpalavra - chave. É açúcar de sintaxe sobre a herança baseada em protótipo existente.

A staticpalavra-chave permite definir facilmente propriedades ou métodos estáticos em uma classe.

Vamos ver o exemplo acima implementado com as classes ES6:

class MyClass {
  // class constructor, equivalent to
  // the function body of a constructor
  constructor() {
    const privateVariable = 'private value'; // Private variable at the constructor scope
    this.publicVariable = 'public value'; // Public property

    this.privilegedMethod = function() {
      // Public Method with access to the constructor scope variables
      console.log(privateVariable);
    };
  }

  // Prototype methods:
  publicMethod() {
    console.log(this.publicVariable);
  }

  // Static properties shared by all instances
  static staticProperty = 'static value';

  static staticMethod() {
    console.log(this.staticProperty);
  }
}

// We can add properties to the class prototype
MyClass.prototype.additionalMethod = function() {
  console.log(this.publicVariable);
};

var myInstance = new MyClass();
myInstance.publicMethod();       // "public value"
myInstance.additionalMethod(); // "public value"
myInstance.privilegedMethod(); // "private value"
MyClass.staticMethod();             // "static value"

CMS
fonte
5
Presumivelmente, privilegedMethodnão é equivalente a um método privado no OO porque parece que poderia ser chamado em uma instância do MyClass? Você quer dizer que é privilegiado porque pode acessar privateVariable?
Donal
3
Não pode this.constructorser usado para acessar as variáveis ​​estáticas de "métodos de instância"? Se sim, vale a pena adicioná-lo à resposta.
Ciro Santilli escreveu
1
Você também pode mencionar funções estáticas no seu exemplo.
David Rodrigues
18
oi, não sei se concordo com esta linha // Variável estática compartilhada por todas as instâncias 'MyClass.staticProperty = "baz";' quanto a mim, deduz que você pode encontrar o baz de 'myInstance.staticProperty', que é claro que não pode.
fullstacklife
5
Talvez devesse ler MyClass.prototype.staticProperty = "baz";ou ser ainda mais correto para os princípios de OO, a propriedade estática deve realmente ser definida como uma função anônima MyClass.prototype.staticProperty = function () {return staticVar;}e para que todas as instâncias acessem uma única variável que também possa ser alterada com um setter.
Lindsaymacvean
535

Você pode aproveitar o fato de que as funções JS também são objetos - o que significa que elas podem ter propriedades.

Por exemplo, citando o exemplo dado no artigo (agora desaparecido) Variáveis ​​estáticas em Javascript :

function countMyself() {
    // Check to see if the counter has been initialized
    if ( typeof countMyself.counter == 'undefined' ) {
        // It has not... perform the initialization
        countMyself.counter = 0;
    }

    // Do something stupid to indicate the value
    alert(++countMyself.counter);
}

Se você chamar essa função várias vezes, verá que o contador está sendo incrementado.

E esta é provavelmente uma solução muito melhor do que poluir o espaço para nome global com uma variável global.


E aqui está outra solução possível, com base em um fechamento: Truque para usar variáveis ​​estáticas em javascript :

var uniqueID = (function() {
   var id = 0; // This is the private persistent value
   // The outer function returns a nested function that has access
   // to the persistent value.  It is this nested function we're storing
   // in the variable uniqueID above.
   return function() { return id++; };  // Return and increment
})(); // Invoke the outer function after defining it.

O que gera o mesmo tipo de resultado - exceto que, desta vez, o valor incrementado é retornado, em vez de exibido.

Pascal MARTIN
fonte
50
como um atalho, você poderia apenas fazer countMyself.counter = countMyself.counter || initial_value;se a variável estática não vai ser Falsey (false, 0, null ou string vazia)
Kip
3
Um pouco mais curto e mais claro: (function () {var id = 0; function uniqueID () {return id ++;};}) ();
Tom Robinson
3
O contador no fechamento é muito mais rápido do que na classe no Firefox. jsperf.com/static-counter-in-class-vs-in-closure
Sony Santos
Use ===para typeofverificações, caso contrário você terá uma coerção estranha.
dewd
@SonySantos seu teste mostra o oposto para o Firefox 40
otrit-bartolo
96

Você faz isso através de um IIFE (expressão de função imediatamente chamada):

var incr = (function () {
    var i = 1;

    return function () {
        return i++;
    }
})();

incr(); // returns 1
incr(); // returns 2
khoomeister
fonte
21
Eu diria que esta é a maneira mais idiomática de fazer isso em JavaScript. Pena que não obtém muitos votos positivos, graças a outros métodos que são provavelmente mais palatáveis ​​para pessoas que vêm de outros idiomas.
1
Eu reformularia usando 'encerramento' em vez de apenas 'IIFE'.
zendka 3/09/19
39

você pode usar o argumento.callee para armazenar variáveis ​​"estáticas" (isso também é útil na função anônima):

function () {
  arguments.callee.myStaticVar = arguments.callee.myStaticVar || 1;
  arguments.callee.myStaticVar++;
  alert(arguments.callee.myStaticVar);
}
gpilotino
fonte
3
Até onde eu entendi, esse método tem uma (apenas uma?) Vantagem sobre o caminho de pascal MARTIN: você pode usá-lo em funções anônimas. Um exemplo disso seria ótimo #
10/10/10 Dan
27
arguments.calleeestá obsoleto.
Perguntas Quolonel
Eu praticamente ridicularizava JS o tempo todo, mas calleeparecia uma coisa agradável de se ter. Gostaria de saber por que o hack eles decidiram depreciar isso ...: |
user2173353
35

Vi algumas respostas semelhantes, mas gostaria de mencionar que este post descreve melhor, por isso, gostaria de compartilhar com você.

Aqui estão alguns códigos retirados dele, que modifiquei para obter um exemplo completo que, esperamos, traga benefícios à comunidade, pois pode ser usado como um modelo de design para as classes.

Ele também responde à sua pergunta:

function Podcast() {

    // private variables
    var _somePrivateVariable = 123;

    // object properties (read/write)
    this.title = 'Astronomy Cast';
    this.description = 'A fact-based journey through the galaxy.';
    this.link = 'http://www.astronomycast.com';

    // for read access to _somePrivateVariable via immutableProp 
    this.immutableProp = function() {
        return _somePrivateVariable;
    }

    // object function
    this.toString = function() {
       return 'Title: ' + this.title;
    }
};

// static property
Podcast.FILE_EXTENSION = 'mp3';
// static function
Podcast.download = function(podcast) {
    console.log('Downloading ' + podcast + ' ...');
};

Dado esse exemplo, você pode acessar as propriedades / funções estáticas da seguinte maneira:

// access static properties/functions
console.log(Podcast.FILE_EXTENSION);   // 'mp3'
Podcast.download('Astronomy cast');    // 'Downloading Astronomy cast ...'

E as propriedades / funções do objeto simplesmente como:

// access object properties/functions
var podcast = new Podcast();
podcast.title = 'The Simpsons';
console.log(podcast.toString());       // Title: The Simpsons
console.log(podcast.immutableProp());  // 123

Observe que em podcast.immutableProp (), temos um fechamento : A referência a _somePrivateVariable é mantida dentro da função.

Você pode até definir getters e setters . Dê uma olhada neste snippet de código (onde dé o protótipo do objeto para o qual você deseja declarar uma propriedade, yé uma variável privada não visível fora do construtor):

// getters and setters
var d = Date.prototype;
Object.defineProperty(d, "year", {
    get: function() {return this.getFullYear() },
    set: function(y) { this.setFullYear(y) }
});

Ele define a propriedade d.yearvia gete setfunções - se você não especificar set, a propriedade é somente leitura e não pode ser modificada (lembre-se de que você não receberá um erro se tentar defini-la, mas não terá efeito). Cada propriedade tem os atributos writable, configurable(permitir que a mudança após a declaração) e enumerable(permitem usá-lo como recenseador), que são por padrão false. Você pode configurá-los via definePropertyno terceiro parâmetro, por exemplo enumerable: true.

O que também é válido é esta sintaxe:

// getters and setters - alternative syntax
var obj = { a: 7, 
            get b() {return this.a + 1;}, 
            set c(x) {this.a = x / 2}
        };

que define uma propriedade legível / gravável a, uma propriedade somente leitura be uma propriedade somente gravação c, através da qual a propriedadea pode ser acessada.

Uso:

console.log(obj.a); console.log(obj.b); // output: 7, 8
obj.c=40;
console.log(obj.a); console.log(obj.b); // output: 20, 21

Notas:

Para evitar comportamentos inesperados, caso você tenha esquecido a newpalavra - chave, sugiro que você adicione o seguinte à função Podcast:

// instantiation helper
function Podcast() {
    if(false === (this instanceof Podcast)) {
        return new Podcast();
    }
// [... same as above ...]
};

Agora, as duas instanciações a seguir funcionarão conforme o esperado:

var podcast = new Podcast(); // normal usage, still allowed
var podcast = Podcast();     // you can omit the new keyword because of the helper

A instrução 'new' cria um novo objeto e copia todas as propriedades e métodos, ou seja,

var a=new Podcast();
var b=new Podcast();
a.title="a"; b.title="An "+b.title;
console.log(a.title); // "a"
console.log(b.title); // "An Astronomy Cast"

Observe também que , em algumas situações, pode ser útil usar a returninstrução na função construtora Podcastpara retornar um objeto personalizado que protege funções nas quais a classe confia internamente, mas que precisa ser exposta. Isso é explicado mais adiante no capítulo 2 (Objetos) da série de artigos.

Você pode dizer isso ae bherdar de Podcast. Agora, e se você quiser adicionar ao Podcast um método que se aplique a todos eles depois ae btenha sido instanciado? Nesse caso, use o .prototypeseguinte:

Podcast.prototype.titleAndLink = function() {
    return this.title + " [" + this.link + "]";
};

Agora ligue ae bnovamente:

console.log(a.titleAndLink()); // "a [http://www.astronomycast.com]"
console.log(b.titleAndLink()); // "An Astronomy Cast [http://www.astronomycast.com]"

Você pode encontrar mais detalhes sobre protótipos aqui . Se você deseja fazer mais herança, sugiro investigar isso .


As séries de artigos que mencionei acima são altamente recomendadas para leitura, incluem também os seguintes tópicos:

  1. Funções
  2. Objetos
  3. Protótipos
  4. Aplicação de novas funções de construtor
  5. Elevação
  6. Inserção automática de ponto e vírgula
  7. Propriedades e métodos estáticos

Observe que o "recurso" automático de inserção de ponto e vírgula do JavaScript (conforme mencionado em 6.) é muitas vezes responsável por causar problemas estranhos no seu código. Por isso, prefiro considerá-lo um bug do que um recurso.

Se você quiser ler mais, aqui está um artigo interessante do MSDN sobre esses tópicos, alguns deles descritos aqui fornecem ainda mais detalhes.

O que é interessante de ler também (também abordando os tópicos mencionados acima) são os artigos do MDN JavaScript Guide :

Se você quiser saber como emular outparâmetros c # (como em DateTime.TryParse(str, out result)) em JavaScript, poderá encontrar um exemplo de código aqui.


Aqueles que estão trabalhando com o IE (que não tem console para JavaScript, a menos que você abra as ferramentas de desenvolvedor usando F12e abra a guia console) podem achar útil o seguinte trecho. Ele permite que você use console.log(msg);como usado nos exemplos acima. Basta inseri-lo antes da Podcastfunção.

Para sua conveniência, veja o código acima em um único trecho de código completo:


Notas:

  • Algumas boas dicas, sugestões e recomendações sobre programação JavaScript em geral, você pode encontrar aqui (práticas recomendadas para JavaScript) e ali ('var' versus 'let') . Também é recomendado este artigo sobre previsões implícitas (coerção) .

  • Uma maneira conveniente de usar classes e compilá-las em JavaScript é o TypeScript. Aqui está um playground onde você pode encontrar alguns exemplos mostrando como funciona. Mesmo que você não esteja usando o TypeScript no momento, é possível ver porque você pode comparar o TypeScript com o resultado do JavaScript em uma exibição lado a lado. A maioria dos exemplos é simples, mas também há um exemplo do Raytracer que você pode experimentar instantaneamente. Eu recomendo olhar especialmente para os exemplos "Using Classes", "Using Inheritance" e "Using Generics" selecionando-os na caixa de combinação - esses são bons modelos que você pode usar instantaneamente em JavaScript. O texto datilografado é usado com Angular.

  • Para obter o encapsulamento de variáveis ​​locais, funções etc. em JavaScript, sugiro usar um padrão como o seguinte (o JQuery usa a mesma técnica):

<html>
<head></head>
<body><script>
    'use strict';
    // module pattern (self invoked function)
    const myModule = (function(context) { 
    // to allow replacement of the function, use 'var' otherwise keep 'const'

      // put variables and function with local module scope here:
      var print = function(str) {
        if (str !== undefined) context.document.write(str);
        context.document.write("<br/><br/>");
        return;
      }
      // ... more variables ...

      // main method
      var _main = function(title) {

        if (title !== undefined) print(title);
        print("<b>last modified:&nbsp;</b>" + context.document.lastModified + "<br/>");        
        // ... more code ...
      }

      // public methods
      return {
        Main: _main
        // ... more public methods, properties ...
      };

    })(this);

    // use module
    myModule.Main("<b>Module demo</b>");
</script></body>
</html>

Obviamente, você pode - e deve - colocar o código do script em um *.jsarquivo separado ; isso é apenas escrito em linha para manter o exemplo curto.

As funções de auto-invocação (também conhecidas como IIFE = Expressão de Função Imediatamente Invocada) são descritas em mais detalhes aqui .

Matt
fonte
28
function Person(){
  if(Person.count == undefined){
    Person.count = 1;
  }
  else{
    Person.count ++;
  }
  console.log(Person.count);
}

var p1 = new Person();
var p2 = new Person();
var p3 = new Person();
jim_zike_huang
fonte
28

Resposta atualizada:

No ECMAScript 6 , você pode criar funções estáticas usando a staticpalavra-chave:

class Foo {

  static bar() {return 'I am static.'}

}

//`bar` is a property of the class
Foo.bar() // returns 'I am static.'

//`bar` is not a property of instances of the class
var foo = new Foo()
foo.bar() //-> throws TypeError

As classes ES6 não introduzem nenhuma nova semântica para estática. Você pode fazer a mesma coisa no ES5 assim:

//constructor
var Foo = function() {}

Foo.bar = function() {
    return 'I am static.'
}

Foo.bar() // returns 'I am static.'

var foo = new Foo()
foo.bar() // throws TypeError

Você pode atribuir a uma propriedade de Fooporque, em funções JavaScript, são objetos.

Max Heiber
fonte
Foo.bar;retorna a função atribuída a ele, não a sequência retornada pela função, como implica o seu comentário.
Você pode adicionar algumas informações sobre como definir (substituir) um valor estático nos dois exemplos?
Wilt
1
@ Nos dois casos, uma propriedade "estática" é apenas uma propriedade da função, então você a define e a substitui como faria com qualquer outra propriedade em JavaScript. Em ambos os casos, você pode definir a barpropriedade Fooda 3assim:Foo.bar = 3;
Max Heiber
Pergunta específica do ES6: stackoverflow.com/questions/28445693/…
Ciro Santilli escreveu:
16

O exemplo e explicação a seguir são do livro Professional JavaScript for Web Developers 2nd Edition, de Nicholas Zakas. Esta é a resposta que eu estava procurando, então pensei que seria útil adicioná-la aqui.

(function () {
    var name = '';
    Person = function (value) {
        name = value;
    };
    Person.prototype.getName = function () {
        return name;
    };
    Person.prototype.setName = function (value) {
        name = value;
    };
}());
var person1 = new Person('Nate');
console.log(person1.getName()); // Nate
person1.setName('James');
console.log(person1.getName()); // James
person1.name = 'Mark';
console.log(person1.name); // Mark
console.log(person1.getName()); // James
var person2 = new Person('Danielle');
console.log(person1.getName()); // Danielle
console.log(person2.getName()); // Danielle

O Personconstrutor neste exemplo tem acesso ao nome da variável privada, assim como os métodos getName()e setName(). Usando esse padrão, a variável name se torna estática e será usada entre todas as instâncias. Isso significa que chamar setName()uma instância afeta todas as outras instâncias. Chamar setName()ou criar uma nova Personinstância define a variável name para um novo valor. Isso faz com que todas as instâncias retornem o mesmo valor.

Nate
fonte
parece construtor + protótipo (híbrido)
Ganesh Kumar
2
Isso coloca o objeto Pessoa no espaço para nome global. Não é uma solução que eu recomendaria.
Ghola
Não acho que seja uma variável estática verdadeira, porque é instanciada de maneira diferente a cada novo objeto. Um objeto estático deve ser consistente em todos os objetos herdados do protótipo pai?
Lindsaymacvean
1
@Ghola A intenção aqui era explicar como criar uma variável estática. Espaços de nomes adequados e evitar globais são um tópico separado que pode ter sido adicionado à complexidade da resposta. Cabe ao usuário determinar como anexar o construtor sem poluir. Se é bom o suficiente para Nicholas Zakas, é bom o suficiente para mim.
Nate
@lindsaymacvean É uma variável estática porque o valor único é compartilhado em todas as instâncias. Não há problema em mudar o valor. Se uma instância alterar o valor, todas as instâncias serão afetadas. Não é provável que seja usado exatamente da mesma forma que o exemplo acima. Permitir que o valor seja definido durante a instanciação é apenas para mostrar que é possível. Um caso de uso mais provável seria ter apenas o getter e o setter ou, pelo menos, verificar se ele está sendo definido como algo diferente de indefinido.
Nate
15

Se você estiver usando a nova sintaxe de classe , poderá fazer o seguinte:

    class MyClass {
      static get myStaticVariable() {
        return "some static variable";
      }
    }

    console.log(MyClass.myStaticVariable);

    aMyClass = new MyClass();
    console.log(aMyClass.myStaticVariable, "is undefined");

Isso efetivamente cria uma variável estática em JavaScript.

Automatico
fonte
Isso é útil ao criar classes de utilitários estáticos!
Indolering
1
Mas agora a questão é como você persiste em um valor e permite alterações nele com um setter. Seria necessário um fechamento ou uma propriedade MyClassdefinida fora da construção de classe.
trincot
Relacionado: stackoverflow.com/questions/28445693/…
Ciro Santilli escreveu:
8

Se você deseja declarar variáveis ​​estáticas para a criação de constantes em seu aplicativo, achei a seguir a abordagem mais simplista

ColorConstants = (function()
{
    var obj = {};
    obj.RED = 'red';
    obj.GREEN = 'green';
    obj.BLUE = 'blue';
    obj.ALL = [obj.RED, obj.GREEN, obj.BLUE];
    return obj;
})();

//Example usage.
var redColor = ColorConstants.RED;
Hemant
fonte
8

Sobre o classintroduzido pelo ECMAScript 2015. As outras respostas não são totalmente claras.

Aqui está um exemplo mostrando como criar uma var estática staticVarcom o ClassName. varsintaxe:

class MyClass {
    constructor(val) {
        this.instanceVar = val;
        MyClass.staticVar = 10;
    }
}

var class1 = new MyClass(1);
console.log(class1.instanceVar);      // 1
console.log(class1.constructor.staticVar); // 10

// New instance of MyClass with another value
var class2 = new MyClass(3);
console.log(class1.instanceVar);      // 1
console.log(class2.instanceVar);      // 3

Para acessar a variável estática, usamos a .constructorpropriedade que retorna uma referência à função construtora de objetos que criou a classe. Podemos chamá-lo nas duas instâncias criadas:

MyClass.staticVar = 11;
console.log(class1.constructor.staticVar); // 11
console.log(class2.constructor.staticVar); // 11 <-- yes it's static! :)

MyClass.staticVar = 12;
console.log(class1.constructor.staticVar); // 12
console.log(class2.constructor.staticVar); // 12
Bobina
fonte
7

Existem outras respostas semelhantes, mas nenhuma delas me atraiu. Aqui está o que eu acabei com:

var nextCounter = (function () {
  var counter = 0;
  return function() {
    var temp = counter;
    counter += 1;
    return temp;
  };
})();
funroll
fonte
7

Além do restante, atualmente há um rascunho (proposta da etapa 2 ) das propostas da ECMA que introduz campos static públicos nas aulas. ( campos particulares foram considerados )

Usando o exemplo da proposta, a staticsintaxe proposta terá a seguinte aparência:

class CustomDate {
  // ...
  static epoch = new CustomDate(0);
}

e ser equivalente ao seguinte, que outros destacaram:

class CustomDate {
  // ...
}
CustomDate.epoch = new CustomDate(0);

Você pode acessá-lo via CustomDate.epoch.

Você pode acompanhar a nova proposta em proposal-static-class-features.


Atualmente, o babel suporta esse recurso com o plug-in de propriedades da classe de transformação que você pode usar. Além disso, embora ainda esteja em andamento, V8está implementando .

Dimitris Fasarakis Hilliard
fonte
6

Você pode criar uma variável estática em JavaScript como esta abaixo. Aqui countestá a variável estática.

var Person = function(name) {
  this.name = name;
  // first time Person.count is undefined, so it is initialized with 1
  // next time the function is called, the value of count is incremented by 1
  Person.count = Person.count ? Person.count + 1 : 1;
}

var p1 = new Person('User p1');
console.log(p1.constructor.count);   // prints 1
var p2 = new Person('User p2');
console.log(p2.constructor.count);   // prints 2

Você pode atribuir valores à variável estática usando a Personfunção ou qualquer uma das instâncias:

// set static variable using instance of Person
p1.constructor.count = 10;         // this change is seen in all the instances of Person
console.log(p2.constructor.count); // prints 10

// set static variable using Person
Person.count = 20;
console.log(p1.constructor.count); // prints 20
Sнаđошƒаӽ
fonte
Essa é uma das boas maneiras de declarar variável estática e acessá-la em JavaScript.
ArunDhwaj IIITH
5

Se você deseja criar uma variável estática global:

var my_id = 123;

Substitua a variável pelo seguinte:

Object.defineProperty(window, 'my_id', {
    get: function() {
            return 123;
        },
    configurable : false,
    enumerable : false
});
JoolzCheat
fonte
4

A coisa mais próxima em JavaScript de uma variável estática é uma variável global - isso é simplesmente uma variável declarada fora do escopo de uma função ou literal de objeto:

var thisIsGlobal = 1;

function foo() {
    var thisIsNot = 2;
}

A outra coisa que você poderia fazer seria armazenar variáveis ​​globais dentro de um objeto literal como este:

var foo = { bar : 1 }

E, em seguida, acessar o variabels assim: foo.bar.

Andrew Hare
fonte
este me ajudou a carregar vários arquivos ..... var foo = {counter: 1}; function moreFiles () {fileName = "File" + foo.counter; foo.counter = foo.counter + 1;
veer7
4

Para condensar todos os conceitos de classe aqui, teste isto:

var Test = function() {
  // "super private" variable, accessible only here in constructor. There are no real private variables
  //if as 'private' we intend variables accessible only by the class that defines the member and NOT by child classes
  var test_var = "super private";

  //the only way to access the "super private" test_var is from here
  this.privileged = function(){
    console.log(test_var);
  }();

  Test.test_var = 'protected';//protected variable: accessible only form inherited methods (prototype) AND child/inherited classes

  this.init();
};//end constructor

Test.test_var = "static";//static variable: accessible everywhere (I mean, even out of prototype, see domready below)

Test.prototype = {

 init:function(){
   console.log('in',Test.test_var);
 }

};//end prototype/class


//for example:
$(document).ready(function() {

 console.log('out',Test.test_var);

 var Jake = function(){}

 Jake.prototype = new Test();

 Jake.prototype.test = function(){
   console.log('jake', Test.test_var);
 }

 var jake = new Jake();

 jake.test();//output: "protected"

});//end domready

Bem, outra maneira de examinar as melhores práticas nessas coisas é ver como o coffeescript traduz esses conceitos.

#this is coffeescript
class Test
 #static
 @prop = "static"

 #instance
 constructor:(prop) ->
   @prop = prop
   console.log(@prop)

 t = new Test('inst_prop');

 console.log(Test.prop);


//this is how the above is translated in plain js by the CS compiler
  Test = (function() {
    Test.prop = "static";

    function Test(prop) {
     this.prop = prop;
     console.log(this.prop);
    }

    return Test;

  })();

  t = new Test('inst_prop');

  console.log(Test.prop);
Luca Reghellin
fonte
4

No JavaScript, as variáveis ​​são estáticas por padrão. Exemplo :

var x = 0;

function draw() {
    alert(x); //
    x+=1;
}

setInterval(draw, 1000);

O valor de x é incrementado em 1 a cada 1000 milissegundos.
Ele imprimirá 1,2,3, etc.

Kerim
fonte
2
Esse é um caso diferente. Seu exemplo é sobre escopos.
Challet 01/12/19
4

Existe outra abordagem, que resolveu meus requisitos depois de navegar neste tópico. Depende exatamente do que você deseja obter com uma "variável estática".

A propriedade global sessionStorage ou localStorage permite que os dados sejam armazenados durante toda a vida útil da sessão ou por um período indefinido por mais tempo, até que sejam explicitamente limpos, respectivamente. Isso permite que os dados sejam compartilhados entre todas as janelas, quadros, painéis de guias, pop-ups, etc. da sua página / aplicativo e é muito mais poderoso do que uma simples "variável estática / global" em um segmento de código.

Evita todos os problemas com o escopo, o tempo de vida, a semântica, a dinâmica etc. das variáveis ​​globais de nível superior, como Window.myglobal. Não sabe o quão eficiente é, mas isso não é importante para quantidades modestas de dados, acessadas a taxas modestas.

Facilmente acessado como "sessionStorage.mydata = qualquer coisa" e recuperado da mesma forma. Consulte "JavaScript: O Guia Definitivo, Sexta Edição", David Flanagan, ISBN: 978-0-596-80552-4, Capítulo 20, seção 20.1. É possível fazer o download deste PDF facilmente por simples pesquisa ou na sua assinatura O'Reilly Safaribooks (vale o peso em ouro).

Greg E
fonte
2

As funções / classes permitem apenas um construtor para o escopo do objeto. Function Hoisting, declarations & expressions

  • As funções criadas com o construtor Function não criam fechamentos para seus contextos de criação; eles sempre são criados no escopo global.

      var functionClass = function ( ) {
            var currentClass = Shape;
            _inherits(currentClass, superClass);
            function functionClass() { superClass.call(this); // Linking with SuperClass Constructor.
                // Instance Variables list.
                this.id = id;   return this;
            }
        }(SuperClass)

Fechamentos - as cópias do fechamento funcionam com dados preservados.

  • As cópias de cada fechamento são criadas para uma função com seus próprios valores ou referências livres. Sempre que você usa a função dentro de outra função, um fechamento é usado.
  • Um fechamento no JavaScript é como manter uma cópia de todas as variáveis ​​locais de sua função pai pelas innerFunctions.

      function closureFun( args ) {
            // Local variable that ends up within closure
            var num = args;
            num++;
            return function() { console.log(num); }
        }
        var closure1 = closureFun( 5 );
        var closure2 = closureFun( 777 );
        closure1(); // 5
        closure2(); // 777
        closure2(); // 778
        closure1(); // 6

Classes de função ES5 : usa Object.defineProperty (O, P, Attributes)

O método Object.defineProperty () define uma nova propriedade diretamente em um objeto ou modifica uma propriedade existente em um objeto e retorna o objeto.

Criou alguns métodos usando `` , para que, de uma só vez, possa entender as classes de função facilmente.

'use strict';
var Shape = function ( superClass ) {
    var currentClass = Shape;
    _inherits(currentClass, superClass); // Prototype Chain - Extends

    function Shape(id) { superClass.call(this); // Linking with SuperClass Constructor.
        // Instance Variables list.
        this.id = id;   return this;
    }
    var staticVariablesJOSN = { "parent_S_V" : 777 };
    staticVariable( currentClass, staticVariablesJOSN );

    // Setters, Getters, instanceMethods. [{}, {}];
    var instanceFunctions = [
        {
            key: 'uniqueID',
            get: function get() { return this.id; },
            set: function set(changeVal) { this.id = changeVal; }
        }
    ];
    instanceMethods( currentClass, instanceFunctions );

    return currentClass;
}(Object);

var Rectangle = function ( superClass ) {
    var currentClass = Rectangle;

    _inherits(currentClass, superClass); // Prototype Chain - Extends

    function Rectangle(id, width, height) { superClass.call(this, id); // Linking with SuperClass Constructor.

        this.width = width;
        this.height = height;   return this;
    }

    var staticVariablesJOSN = { "_staticVar" : 77777 };
    staticVariable( currentClass, staticVariablesJOSN );

    var staticFunctions = [
        {
            key: 'println',
            value: function println() { console.log('Static Method'); }
        }
    ];
    staticMethods(currentClass, staticFunctions);

    var instanceFunctions = [
        {
            key: 'setStaticVar',
            value: function setStaticVar(staticVal) {
                currentClass.parent_S_V = staticVal;
                console.log('SET Instance Method Parent Class Static Value : ', currentClass.parent_S_V);
            }
        }, {
            key: 'getStaticVar',
            value: function getStaticVar() {
                console.log('GET Instance Method Parent Class Static Value : ', currentClass.parent_S_V);
                return currentClass.parent_S_V;
            }
        }, {
            key: 'area',
            get: function get() {
                console.log('Area : ', this.width * this.height);
                return this.width * this.height;
                }
        }, {
            key: 'globalValue',
            get: function get() {
                console.log('GET ID : ', currentClass._staticVar);
                return currentClass._staticVar;
            },
            set: function set(value) {
                currentClass._staticVar = value;
                console.log('SET ID : ', currentClass._staticVar);
            }
        }
    ];
    instanceMethods( currentClass, instanceFunctions );

    return currentClass;
}(Shape);

// ===== ES5 Class Conversion Supported Functions =====
function defineProperties(target, props) {
    console.log(target, ' : ', props);
    for (var i = 0; i < props.length; i++) {
        var descriptor = props[i];
        descriptor.enumerable = descriptor.enumerable || false;
        descriptor.configurable = true;
        if ("value" in descriptor) descriptor.writable = true;
        Object.defineProperty(target, descriptor.key, descriptor);
    }
}
function staticMethods( currentClass, staticProps ) {
    defineProperties(currentClass, staticProps);
};
function instanceMethods( currentClass, protoProps ) {
    defineProperties(currentClass.prototype, protoProps);
};
function staticVariable( currentClass, staticVariales ) {
    // Get Key Set and get its corresponding value.
    // currentClass.key = value;
    for( var prop in staticVariales ) {
        console.log('Keys : Values');
        if( staticVariales.hasOwnProperty( prop ) ) {
            console.log(prop, ' : ', staticVariales[ prop ] );
            currentClass[ prop ] = staticVariales[ prop ];
        }
    }
};
function _inherits(subClass, superClass) {
    console.log( subClass, ' : extends : ', superClass );
    if (typeof superClass !== "function" && superClass !== null) {
        throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
    }
    subClass.prototype = Object.create(superClass && superClass.prototype, 
            { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } });
    if (superClass)
        Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
}

Abaixo, o snippet de código é testar sobre cada instância tem sua própria cópia dos membros da instância e membros estáticos comuns.

var objTest = new Rectangle('Yash_777', 8, 7);
console.dir(objTest);

var obj1 = new Rectangle('R_1', 50, 20);
Rectangle.println(); // Static Method
console.log( obj1 );    // Rectangle {id: "R_1", width: 50, height: 20}
obj1.area;              // Area :  1000
obj1.globalValue;       // GET ID :  77777
obj1.globalValue = 88;  // SET ID :  88
obj1.globalValue;       // GET ID :  88  

var obj2 = new Rectangle('R_2', 5, 70);
console.log( obj2 );    // Rectangle {id: "R_2", width: 5, height: 70}
obj2.area;              // Area :  350    
obj2.globalValue;       // GET ID :  88
obj2.globalValue = 999; // SET ID :  999
obj2.globalValue;       // GET ID :  999

console.log('Static Variable Actions.');
obj1.globalValue;        // GET ID :  999

console.log('Parent Class Static variables');
obj1.getStaticVar();    // GET Instance Method Parent Class Static Value :  777
obj1.setStaticVar(7);   // SET Instance Method Parent Class Static Value :  7
obj1.getStaticVar();    // GET Instance Method Parent Class Static Value :  7

As chamadas de método estático são feitas diretamente na classe e não podem ser chamadas em instâncias da classe. Mas você pode atender às chamadas de membros estáticos de dentro de uma instância.

Usando sintaxe:

   this.constructor.staticfunctionName();
class MyClass {
    constructor() {}
    static staticMethod() {
        console.log('Static Method');
    }
}
MyClass.staticVar = 777;

var myInstance = new MyClass();
// calling from instance
myInstance.constructor.staticMethod();
console.log('From Inside Class : ',myInstance.constructor.staticVar);

// calling from class
MyClass.staticMethod();
console.log('Class : ', MyClass.staticVar);

Classes ES6: as classes ES2015 são um açúcar simples sobre o padrão OO baseado em protótipo. Ter um único formulário declarativo conveniente facilita o uso de padrões de classe e incentiva a interoperabilidade. As classes suportam herança baseada em protótipo, super chamadas, instância e métodos estáticos e construtores.

Exemplo : consulte meu post anterior.

Yash
fonte
2

Existem 4 maneiras de emular variáveis ​​estáticas de função local em Javascript.

Método 1: Usando propriedades do objeto de função (suportadas em navegadores antigos)

function someFunc1(){
    if( !('staticVar' in someFunc1) )
        someFunc1.staticVar = 0 ;
    alert(++someFunc1.staticVar) ;
}

someFunc1() ; //prints 1
someFunc1() ; //prints 2
someFunc1() ; //prints 3

Método 2: usando um fechamento, variante 1 (suportada em navegadores antigos)

var someFunc2 = (function(){
    var staticVar = 0 ;
    return function(){
        alert(++staticVar) ;
    }
})()

someFunc2() ; //prints 1
someFunc2() ; //prints 2
someFunc2() ; //prints 3

Método 3: usando um fechamento, variante 2 (também suportada em navegadores antigos)

var someFunc3 ;
with({staticVar:0})
    var someFunc3 = function(){
        alert(++staticVar) ;
    }

someFunc3() ; //prints 1
someFunc3() ; //prints 2
someFunc3() ; //prints 3

Método 4: usando um fechamento, variante 3 (requer suporte para EcmaScript 2015)

{
    let staticVar = 0 ;
    function someFunc4(){
        alert(++staticVar) ;
    }
}

someFunc4() ; //prints 1
someFunc4() ; //prints 2
someFunc4() ; //prints 3
Liberta-te
fonte
2

Você pode definir funções estáticas no JavaScript usando a staticpalavra-chave:

class MyClass {
  static myStaticFunction() {
    return 42;
  }
}

MyClass.myStaticFunction(); // 42

No momento da redação deste texto, você ainda não pode definir propriedades estáticas (exceto funções) dentro da classe. As propriedades estáticas ainda são uma proposta do Estágio 3 , o que significa que ainda não fazem parte do JavaScript. No entanto, não há nada que o impeça de simplesmente atribuir a uma classe como você faria com qualquer outro objeto:

class MyClass {}

MyClass.myStaticProperty = 42;

MyClass.myStaticProperty; // 42

Nota final: tenha cuidado ao usar objetos estáticos com herança - todas as classes herdadas compartilham a mesma cópia do objeto .

vkarpov15
fonte
1

No JavaScript, não há termo ou palavra-chave estática, mas podemos colocar esses dados diretamente no objeto de função (como em qualquer outro objeto).

function f() {
    f.count = ++f.count || 1 // f.count is undefined at first
    alert("Call No " + f.count)
}

f(); // Call No 1

f(); // Call No 2
Satyapriya Mishra
fonte
1

Eu uso muito variáveis ​​de função estática e é uma pena que o JS não tenha um mecanismo interno para isso. Muitas vezes vejo código em que variáveis ​​e funções são definidas em um escopo externo, mesmo que sejam usadas apenas dentro de uma função. Isso é feio, propenso a erros e apenas pede problemas ...

Eu vim com o seguinte método:

if (typeof Function.prototype.statics === 'undefined') {
  Function.prototype.statics = function(init) {
    if (!this._statics) this._statics = init ? init() : {};
    return this._statics;
  }
}

Isso adiciona um método 'estático' a todas as funções (sim, apenas relaxe), quando chamado, adiciona um objeto vazio (_statics) ao objeto de função e o retorna. Se uma função init for fornecida, _statics será definido como resultado init ().

Você pode então fazer:

function f() {
  const _s = f.statics(() => ({ v1=3, v2=somefunc() });

  if (_s.v1==3) { ++_s.v1; _s.v2(_s.v1); }
} 

Comparando isso com um IIFE que é a outra resposta correta, isso tem a desvantagem de adicionar uma atribuição e uma se a cada chamada de função e adicionar um membro '_statics' à função, no entanto, existem algumas vantagens: os argumentos estão disponíveis em a parte superior que não está na função interna, o uso de 'estático' no código da função interna é explícito com um '_s'. prefixo, e é geralmente mais simples olhar e entender.

kofifus
fonte
1

Resumo:

No ES6/ ES 2015, a classpalavra - chave foi introduzida com uma staticpalavra-chave acompanhada . Lembre-se de que este é o açúcar sintático do modelo de herança prototípica que o javavscript incorpora. A staticpalavra-chave funciona da seguinte maneira para métodos:

class Dog {

  static bark () {console.log('woof');}
  // classes are function objects under the hood
  // bark method is located on the Dog function object
  
  makeSound () { console.log('bark'); }
  // makeSound is located on the Dog.prototype object

}

// to create static variables just create a property on the prototype of the class
Dog.prototype.breed = 'Pitbull';
// So to define a static property we don't need the `static` keyword.

const fluffy = new Dog();
const vicky = new Dog();
console.log(fluffy.breed, vicky.breed);

// changing the static variable changes it on all the objects
Dog.prototype.breed = 'Terrier';
console.log(fluffy.breed, vicky.breed);

Willem van der Veen
fonte
2
Ele estava pedindo uma variável estática, não uma função estática.
Konrad Höffner
1

Eu usei o protótipo e assim funcionou:

class Cat extends Anima {
  constructor() {
    super(Cat.COLLECTION_NAME);
  }
}

Cat.COLLECTION_NAME = "cats";

ou usando um getter estático:

class Cat extends Anima {
  constructor() {
    super(Cat.COLLECTION_NAME);
  }

  static get COLLECTION_NAME() {
    return "cats"
  }
}
EliuX
fonte
0

As variáveis ​​no nível da janela são como estáticas no sentido de que você pode usar referência direta e elas estão disponíveis para todas as partes do seu aplicativo

Bostone
fonte
3
Uma descrição muito melhor desses vars é "global", e não estática.
Patrick M
0

Não existe uma variável estática no Javascript. Essa linguagem é orientada a objetos com base em protótipos, portanto, não há classes, mas protótipos de onde os objetos se "copiam".

Você pode simulá-los com variáveis ​​globais ou com prototipagem (adicionando uma propriedade ao protótipo):

function circle(){
}
circle.prototype.pi=3.14159
Gerardo
fonte
Este método funciona, mas você está poluindo oFunction.prototype
Dan
@ Dan: É meu entendimento que isso seria apenas para o círculo e não a função. Pelo menos é o que o Chrome tenta me dizer: function circle() {}| circle.prototype| circle.prototype.pi = 3.14| circle.prototype| Function.prototype| Function.__proto__(se é isso que você quis dizer)
Aktau
0

Trabalhando com sites MVC que usam jQuery, gosto de garantir que as ações do AJAX em determinados manipuladores de eventos só possam ser executadas quando a solicitação anterior for concluída. Eu uso uma variável de objeto jqXHR "estática" para conseguir isso.

Dado o seguinte botão:

<button type="button" onclick="ajaxAction(this, { url: '/SomeController/SomeAction' })">Action!</button>

Eu geralmente uso um IIFE como este para meu manipulador de cliques:

var ajaxAction = (function (jqXHR) {
    return function (sender, args) {
        if (!jqXHR || jqXHR.readyState == 0 || jqXHR.readyState == 4) {
            jqXHR = $.ajax({
                url: args.url,
                type: 'POST',
                contentType: 'application/json',
                data: JSON.stringify($(sender).closest('form').serialize()),
                success: function (data) {
                    // Do something here with the data.
                }
            });
        }
    };
})(null);
Todd L
fonte
0

Se você quiser usar o protótipo, existe uma maneira

var p = function Person() {
    this.x = 10;
    this.y = 20;
}
p.prototype.counter = 0;
var person1 = new p();
person1.prototype = p.prototype;
console.log(person1.counter);
person1.prototype.counter++;
var person2 = new p();
person2.prototype = p.prototype;
console.log(person2.counter);
console.log(person1.counter);

Fazendo isso, você poderá acessar a variável do contador a partir de qualquer instância e qualquer alteração na propriedade será refletida imediatamente !!

Charlie
fonte