Variabili statiche in JavaScript


716

Come posso creare variabili statiche in Javascript?


possiamo definire un'etichetta o un altro tag html con l'attributo di stile "dispaly: none" e impostare il valore variabile per questo valore e l'operazione su questo valore. Non prendiamoci duro.
asghar,

La soluzione più semplice che ho trovato: non definire affatto una variabile statica nella classe. Quando si desidera utilizzare una variabile statica, è sufficiente definirla lì e quindi, ad es someFunc = () => { MyClass.myStaticVariable = 1; }. Quindi basta creare un metodo statico per restituire il membro statico, ad es static getStatic() { return MyClass.myStaticVariable; }. Quindi puoi semplicemente chiamare MyClass.getStatic()dall'esterno della classe per ottenere i dati statici!
Pixel

Risposte:


863

Se provieni da un linguaggio orientato agli oggetti di tipo statico e basato sulla classe (come Java, C ++ o C #) presumo che stai cercando di creare una variabile o un metodo associato a un "tipo" ma non a un'istanza.

Un esempio che utilizza un approccio "classico", con funzioni di costruzione potrebbe forse aiutarti a cogliere i concetti di base OO JavaScript:

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è definito nell'oggetto MyClass (che è una funzione) e non ha nulla a che fare con le sue istanze create, JavaScript considera le funzioni come oggetti di prima classe , quindi essendo un oggetto, è possibile assegnare proprietà a una funzione.

AGGIORNAMENTO: ES6 ha introdotto la possibilità di dichiarare le classi tramite la classparola chiave. È lo zucchero sintattico sull'eredità esistente basata sul prototipo.

La staticparola chiave consente di definire facilmente proprietà o metodi statici in una classe.

Vediamo l'esempio sopra implementato con le classi 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"


5
Presumibilmente privilegedMethodnon è equivalente a un metodo privato in OO perché sembra che potrebbe essere chiamato su un'istanza di MyClass? Vuoi dire che è privilegiato perché può accedere privateVariable?
Dónal,

3
Non può this.constructoressere utilizzato per accedere alle variabili statiche da "metodi di istanza"? Se sì, vale la pena aggiungerlo alla risposta.
Ciro Santilli 22 冠状 病 六四 事件 法轮功

1
Potresti anche menzionare le funzioni statiche nel tuo esempio.
David Rodrigues,

18
ciao, non sono sicuro di essere d'accordo con questa riga // Variabile statica condivisa da tutte le istanze 'MyClass.staticProperty = "baz";' quanto a me che deduce che puoi trovare baz da 'myInstance.staticProperty' che ovviamente non puoi.
fullstacklife

5
Forse dovrebbe leggere MyClass.prototype.staticProperty = "baz";o per essere ancora più corretto ai principi OO la proprietà statica dovrebbe essere definita come una funzione anonimaMyClass.prototype.staticProperty = function () {return staticVar;} e in modo che tutte le istanze accedano a una singola variabile che potrebbe anche essere modificata con un setter.
Lindsaymacvean,

535

Potresti trarre vantaggio dal fatto che anche le funzioni JS sono oggetti, il che significa che possono avere proprietà.

Ad esempio, citando l'esempio fornito sull'articolo (ora scomparso) Variabili statiche in 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 chiamate quella funzione più volte, vedrete che il contatore viene incrementato.

E questa è probabilmente una soluzione molto migliore rispetto all'inquinamento dello spazio dei nomi globale con una variabile globale.


Ed ecco un'altra possibile soluzione, basata su una chiusura: Trucco per utilizzare le variabili statiche in 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.

Che ti dà lo stesso tipo di risultato - tranne, questa volta, viene restituito il valore incrementato, anziché visualizzato.


50
come scorciatoia, potresti fare solo countMyself.counter = countMyself.counter || initial_value;se la variabile statica non sarà mai falsa (false, 0, null o stringa vuota)
Kip

3
Leggermente più breve e più chiaro: (function () {var id = 0; function uniqueID () {return id ++;};}) ();
Tom Robinson,

3
Il contatore in chiusura è molto più veloce rispetto alla classe di Firefox. jsperf.com/static-counter-in-class-vs-in-closure
Sony Santos

Usa ===per i typeofcontrolli altrimenti otterrai una strana coercizione in corso.
rugiada del

@SonySantos Il tuo test mostra il contrario per Firefox 40
bartolo-otrit

96

Lo fai attraverso un IIFE (espressione di funzione immediatamente invocata):

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

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

incr(); // returns 1
incr(); // returns 2

21
Direi che questo è il modo più idiomatico per farlo in JavaScript. Peccato che non ottenga troppi voti grazie ad altri metodi che sono probabilmente più appetibili per le persone che provengono da altre lingue.

1
Riformulerei usando 'chiusura' piuttosto che solo 'IIFE'.
Zendka,

39

puoi usare argomenti.callee per memorizzare variabili "statiche" (utile anche in funzione anonima):

function () {
  arguments.callee.myStaticVar = arguments.callee.myStaticVar || 1;
  arguments.callee.myStaticVar++;
  alert(arguments.callee.myStaticVar);
}

3
Per quanto posso capire, questo metodo ha un (solo uno?) Vantaggio rispetto a Pascal MARTIN: puoi usarlo su funzioni anonime. Un esempio di questo sarebbe fantastico
Dan,

27
arguments.calleeè deprecato.
Quolonel Domande

Praticamente ridicolo JS tutto il tempo, ma mi è calleesembrato una cosa carina. Mi chiedo perché l'hacking abbiano deciso di deprecare questo ...: |
user2173353

35

Ho visto un paio di risposte simili, ma vorrei menzionare questo post descrive meglio, quindi mi piacerebbe condividerlo con te.

Ecco un po 'di codice preso da esso, che ho modificato per ottenere un esempio completo che si spera possa dare vantaggi alla comunità perché può essere usato come modello di progettazione per le classi.

Risponde anche alla tua domanda:

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 + ' ...');
};

Dato questo esempio, puoi accedere alle proprietà / funzioni statiche come segue:

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

E l' oggetto proprietà / funzioni semplicemente come:

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

Nota che in podcast.immutableProp (), abbiamo una chiusura : il riferimento a _somePrivateVariable è mantenuto all'interno della funzione.

Puoi persino definire getter e setter . Dai un'occhiata a questo frammento di codice (dove si dtrova il prototipo dell'oggetto per il quale vuoi dichiarare una proprietà, yè una variabile privata non visibile al di fuori del costruttore):

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

Definisce la proprietà d.yeartramite gete le setfunzioni: se non si specifica set, la proprietà è di sola lettura e non può essere modificata (tenere presente che non si verificherà un errore se si tenta di impostarla, ma non ha alcun effetto). Ogni proprietà ha gli attributi writable, configurable(consentire ai cambiamenti dopo la dichiarazione) e enumerable(permette di usarlo come enumeratore), che sono per impostazione predefinita false. È possibile impostarli tramite definePropertynel terzo parametro, ad es enumerable: true.

Ciò che è anche valido è questa sintassi:

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

che definisce una proprietà leggibile / scrivibile a, una proprietà di sola lettura be una proprietà di sola scrittura c, attraverso la quale è apossibile accedere alla proprietà .

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

Appunti:

Per evitare comportamenti imprevisti nel caso in cui hai dimenticato la newparola chiave, ti suggerisco di aggiungere quanto segue alla funzione Podcast:

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

Ora entrambe le seguenti istanze funzioneranno come previsto:

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

L'istruzione "new" crea un nuovo oggetto e copia tutte le proprietà e i metodi, ad es

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"

Si noti inoltre che in alcune situazioni può essere utile utilizzare l' returnistruzione nella funzione di costruzionePodcast per restituire un oggetto personalizzato che protegge le funzioni su cui la classe si basa internamente ma che devono essere esposte. Questo è spiegato ulteriormente nel capitolo 2 (Oggetti) della serie di articoli.

Puoi dirlo aed bereditare da Podcast. Ora, cosa succede se si desidera aggiungere un metodo al Podcast che si applica a tutti dopo ae che bè stato istanziato? In questo caso, utilizzare .prototypequanto segue:

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

Adesso chiama ae bancora:

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

Puoi trovare maggiori dettagli sui prototipi qui . Se vuoi fare più eredità, suggerisco di esaminare questo .


Le serie di articoli che ho menzionato sopra sono altamente raccomandate da leggere, includono anche i seguenti argomenti:

  1. funzioni
  2. Oggetti
  3. prototipi
  4. Applicazione di nuove funzioni per costruttori
  5. sollevamento
  6. Inserimento automatico punto e virgola
  7. Proprietà e metodi statici

Si noti che l' inserimento automatico del punto e virgola "funzione" di di JavaScript (come menzionato in 6.) è spesso responsabile di causare strani problemi nel codice. Quindi, preferirei considerarlo un bug piuttosto che una funzionalità.

Se vuoi leggere di più, ecco un articolo MSDN piuttosto interessante su questi argomenti, alcuni dei quali descritti forniscono ulteriori dettagli.

Ciò che è interessante da leggere (che coprono anche gli argomenti sopra menzionati) sono quegli articoli della Guida JavaScript MDN :

Se vuoi sapere come emulare i outparametri c # (come in DateTime.TryParse(str, out result)) in JavaScript, puoi trovare il codice di esempio qui.


Quelli di voi che lavorano con IE (che non ha una console per JavaScript a meno che non apriate gli strumenti di sviluppo usando F12e aprite la scheda della console) potrebbero trovare utile il seguente frammento. Ti permette di usare console.log(msg);come usato negli esempi sopra. Basta inserirlo prima della Podcastfunzione.

Per comodità, ecco il codice sopra in uno snippet di codice singolo completo:


Appunti:

  • Alcuni buoni consigli, suggerimenti e raccomandazioni sulla programmazione JavaScript in generale sono disponibili qui (best practice JavaScript) e lì ('var' contro 'let') . Inoltre è raccomandato questo articolo sui dattiloscritti impliciti (coercizione) .

  • Un modo conveniente per usare le classi e compilarle in JavaScript è TypeScript. Ecco un parco giochi dove puoi trovare alcuni esempi che mostrano come funziona. Anche se al momento non stai usando TypeScript, puoi dare un'occhiata perché puoi confrontare TypeScript con il risultato JavaScript in una vista affiancata. La maggior parte degli esempi sono semplici, ma c'è anche un esempio Raytracer che puoi provare all'istante. Consiglio in particolare di esaminare gli esempi "Uso delle classi", "Uso dell'ereditarietà" e "Uso dei generici" selezionandoli nella casella combinata: questi sono dei bei modelli che puoi usare istantaneamente in JavaScript. Typescript è usato con Angular.

  • Per ottenere l' incapsulamento di variabili locali, funzioni ecc. In JavaScript, suggerisco di utilizzare uno schema come il seguente (JQuery utilizza la stessa tecnica):

<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>

Ovviamente, puoi - e dovresti - inserire il codice dello script in un *.jsfile separato ; questo è solo scritto in linea per mantenere l'esempio breve.

Le funzioni di auto-invocazione (note anche come IIFE = Espressione di funzione immediatamente richiamata) sono descritte più dettagliatamente qui .


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();

28

Risposta aggiornata:

In ECMAScript 6 , è possibile creare funzioni statiche utilizzando la staticparola chiave:

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

Le classi ES6 non introducono alcuna nuova semantica per la statica. Puoi fare la stessa cosa in ES5 in questo modo:

//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

È possibile assegnare a una proprietà di Fooperché in JavaScript le funzioni sono oggetti.


Foo.bar;restituisce la funzione assegnata ad essa, non la stringa restituita dalla funzione come implica il commento.

Puoi aggiungere alcune informazioni su come impostare (sovrascrivere) un valore statico in entrambi gli esempi?
Wilt,

1
@Wilt in entrambi i casi, una proprietà "statica" è solo una proprietà della funzione, quindi la imposti e la sovrascrivi proprio come faresti con qualsiasi altra proprietà in JavaScript. In entrambi i casi, è possibile impostare la barproprietà di Fooa 3come questo:Foo.bar = 3;
Max Heiber


16

L'esempio e la spiegazione seguenti sono tratti dal libro Professional JavaScript for Web Developers 2nd Edition di Nicholas Zakas. Questa è la risposta che stavo cercando, quindi ho pensato che sarebbe stato utile aggiungerlo qui.

(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

Il Personcostruttore in questo esempio ha accesso al nome della variabile privata, così come i metodi getName()e setName(). Usando questo modello, la variabile name diventa statica e verrà usata tra tutte le istanze. Questo significa che chiamare setName()un'istanza influisce su tutte le altre istanze. La chiamata setName()o la creazione di una nuova Personistanza imposta la variabile del nome su un nuovo valore. Ciò fa sì che tutte le istanze restituiscano lo stesso valore.


sembra costruttore + prototipo (ibrido)
Ganesh Kumar il

2
Ciò posiziona l'oggetto Person nello spazio dei nomi globale. Non è una soluzione che consiglierei.
Ghola,

Non penso che questa sia una vera variabile statica perché è istanziata in modo diverso con ogni nuovo oggetto. Un oggetto statico dovrebbe essere coerente tra tutti gli oggetti ereditati dal prototipo padre?
Lindsaymacvean,

1
@Ghola L'intenzione qui era di spiegare come creare una variabile statica. La corretta spaziatura dei nomi ed evitare i globi è un argomento separato che può aver aggiunto alla complessità della risposta. Spetta all'utente determinare come collegare il costruttore senza inquinare. Se è abbastanza buono per Nicholas Zakas, è abbastanza buono per me.
Nate,

@lindsaymacvean È una variabile statica perché il singolo valore è condiviso in tutte le istanze. Va bene che il valore cambi. Se un'istanza modifica il valore, saranno interessate tutte le istanze. Non è probabile che sarebbe usato esattamente come nell'esempio sopra. Consentire il valore da impostare durante l'istanza è solo per mostrare che è possibile. Un caso d'uso più probabile sarebbe avere solo il getter e il setter o almeno verificare per assicurarsi che sia impostato su qualcosa di diverso da undefined.
Nate,

15

Se si utilizza la nuova sintassi della classe, ora è possibile effettuare le seguenti operazioni:

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

    console.log(MyClass.myStaticVariable);

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

Questo crea effettivamente una variabile statica in JavaScript.


Ciò è utile quando si creano classi di utilità statiche!
Indolente il

1
Ma ora la domanda è: come persisti un valore e permetti di modificarlo con un setter. Sarebbe necessaria una chiusura o una proprietà MyClassdefinita al di fuori del costrutto di classe.
trincot


8

Se vuoi dichiarare variabili statiche per la creazione di costanti nella tua applicazione, ho trovato il seguente approccio più semplicistico

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;

8

Riguardo a class sull'introduzione di ECMAScript 2015. Le altre risposte non sono del tutto chiare.

Ecco un esempio che mostra come creare una var statica staticVarcon ClassName. varsynthax:

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

Per accedere alla variabile statica utilizziamo la .constructorproprietà che restituisce un riferimento alla funzione di costruzione oggetti che ha creato la classe. Possiamo chiamarlo nelle due istanze create:

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

7

Ci sono altre risposte simili, ma nessuna mi ha attirato. Ecco cosa ho finito con:

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

7

Oltre al resto, esiste attualmente una bozza (proposta fase 2 ) sulle proposte ECMA che introduce campi static pubblici nelle classi. ( sono stati considerati campi privati )

Utilizzando l'esempio della proposta, la staticsintassi proposta sarà simile a questa:

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

ed essere equivalente al seguente che altri hanno sottolineato:

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

È quindi possibile accedervi tramite CustomDate.epoch.

Puoi tenere traccia della nuova proposta in proposal-static-class-features.


Attualmente, babel supporta questa funzione con il plug-in delle proprietà della classe di trasformazione che è possibile utilizzare. Inoltre, sebbene sia ancora in corso, lo V8sta implementando .


6

È possibile creare una variabile statica in JavaScript come questa di seguito. Ecco countla variabile statica.

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

È possibile assegnare valori alla variabile statica utilizzando la Personfunzione o una qualsiasi delle istanze:

// 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

Questo è uno dei migliori approcci per dichiarare la variabile statica e accedervi in ​​JavaScript.
ArunDhwaj IIITH

5

Se si desidera creare una variabile statica globale:

var my_id = 123;

Sostituisci la variabile con la seguente:

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

4

La cosa più vicina in JavaScript a una variabile statica è una variabile globale - questa è semplicemente una variabile dichiarata al di fuori dell'ambito di una funzione o di un oggetto letterale:

var thisIsGlobal = 1;

function foo() {
    var thisIsNot = 2;
}

L'altra cosa che potresti fare sarebbe memorizzare variabili globali all'interno di un oggetto letterale come questo:

var foo = { bar : 1 }

E quindi accedere alla variabels in questo modo: foo.bar.


questo mi ha aiutato a caricare più file ..... var foo = {counter: 1}; function moreFiles () {fileName = "File" + foo.counter; foo.counter = foo.counter + 1;
Veer7,

4

Per condensare tutti i concetti di classe qui, prova questo:

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

Bene, un altro modo di dare un'occhiata alle migliori pratiche in queste cose è vedere come coffeescript traduce questi concetti.

#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);

4

In JavaScript le variabili sono statiche per impostazione predefinita. Esempio :

var x = 0;

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

setInterval(draw, 1000);

Il valore di x viene aumentato di 1 ogni 1000 millisecondi.
Verrà stampato 1,2,3 e così via


2
È un caso diverso. Il tuo esempio riguarda gli ambiti.
challet,

4

C'è un altro approccio, che ha risolto i miei requisiti dopo aver cercato questa discussione. Dipende esattamente da cosa vuoi ottenere con una "variabile statica".

La proprietà globale sessionStorage o localStorage consente di archiviare i dati per la durata della sessione o per un periodo indefinito più lungo fino a quando non vengono esplicitamente cancellati, rispettivamente. Ciò consente di condividere i dati tra tutte le finestre, i frame, i pannelli delle schede, i popup, ecc. Della pagina / app ed è molto più potente di una semplice "variabile statica / globale" in un segmento di codice.

Evita ogni seccatura con l'ambito, la durata, la semantica, la dinamica ecc. Delle variabili globali di massimo livello, ovvero Window.myglobal. Non so quanto sia efficiente, ma non è importante per modeste quantità di dati, accessibili a tariffe modeste.

Facilmente accessibile come "sessionStorage.mydata = any" e recuperato in modo simile. Vedi "JavaScript: The Definitive Guide, Sixth Edition", David Flanagan, ISBN: 978-0-596-80552-4, capitolo 20, sezione 20.1. Questo è facilmente scaricabile in PDF con una semplice ricerca o nel tuo abbonamento O'Reilly Safaribooks (vale il suo peso in oro).


2

Le funzioni / classi consentono solo un singolo costruttore per l'ambito dell'oggetto. Function Hoisting, declarations & expressions

  • Le funzioni create con il costruttore Function non creano chiusure ai loro contesti di creazione; sono sempre creati nell'ambito globale.

      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)

Chiusure : le copie di chiusura funzionano con i dati conservati.

  • Le copie di ogni chiusura vengono create in una funzione con i propri valori o riferimenti liberi. Ogni volta che si utilizza la funzione all'interno di un'altra funzione, viene utilizzata una chiusura.
  • Una chiusura in JavaScript è come mantenere una copia di tutte le variabili locali della sua funzione padre da parte delle funzioni interne.

      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

Classi di funzioni ES5 : utilizza Object.defineProperty (O, P, Attributi)

Il metodo Object.defineProperty () definisce una nuova proprietà direttamente su un oggetto o modifica una proprietà esistente su un oggetto e restituisce l'oggetto.

Creato alcuni metodi usando `` , in modo che ogni volta sia possibile capire facilmente le classi di funzioni.

'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;
}

Sotto lo snippet di codice c'è da verificare su Ogni istanza ha la propria copia dei membri dell'istanza e dei membri statici comuni.

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

Le chiamate ai metodi statici vengono effettuate direttamente sulla classe e non sono richiamabili su istanze della classe. Ma puoi ottenere le chiamate per i membri statici dall'interno di un'istanza.

Utilizzando la sintassi:

   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);

Classi ES6: le classi ES2015 sono un semplice zucchero sul modello OO basato su prototipo. Avere un unico comodo modulo dichiarativo semplifica l'uso dei modelli di classe e incoraggia l'interoperabilità. Le classi supportano eredità basata su prototipo, super chiamate, metodi e costruttori statici e di istanza.

Esempio : consultare il mio post precedente.


2

Esistono 4 modi per emulare le variabili statiche locali della funzione in Javascript.

Metodo 1: utilizzo delle proprietà dell'oggetto funzione (supportato nei browser precedenti)

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

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

Metodo 2: utilizzo di una chiusura, variante 1 (supportata nei browser precedenti)

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

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

Metodo 3: utilizzo di una chiusura, variante 2 (supportata anche nei browser precedenti)

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

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

Metodo 4: utilizzo di una chiusura, variante 3 (richiede il supporto per EcmaScript 2015)

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

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

2

Puoi definire funzioni statiche in JavaScript usando la staticparola chiave:

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

MyClass.myStaticFunction(); // 42

Al momento della stesura di questo documento, non è ancora possibile definire proprietà statiche (diverse dalle funzioni) all'interno della classe. Le proprietà statiche sono ancora una proposta Stage 3 , il che significa che non fanno ancora parte di JavaScript. Tuttavia, non c'è nulla che ti impedisca di assegnare semplicemente a una classe come faresti con qualsiasi altro oggetto:

class MyClass {}

MyClass.myStaticProperty = 42;

MyClass.myStaticProperty; // 42

Nota finale: fare attenzione all'utilizzo di oggetti statici con ereditarietà - tutte le classi ereditate condividono la stessa copia dell'oggetto .


1

In JavaScript non esiste un termine o una parola chiave statici, ma possiamo inserire tali dati direttamente nell'oggetto funzione (come in qualsiasi altro oggetto).

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

1

Uso molto le variabili di funzione statica ed è un vero peccato JS non ha un meccanismo incorporato per questo. Troppo spesso vedo il codice in cui le variabili e le funzioni sono definite in un ambito esterno anche se sono usate solo all'interno di una funzione. Questo è brutto, soggetto a errori e solo chiedendo problemi ...

Ho escogitato il seguente metodo:

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

Ciò aggiunge un metodo "statico" a tutte le funzioni (sì, basta rilassarsene), quando viene chiamato aggiungerà un oggetto vuoto (_statics) all'oggetto funzione e lo restituirà. Se viene fornita una funzione init, _statics verrà impostato sul risultato init ().

È quindi possibile fare:

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

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

Confrontando questo con un IIFE che è l'altra risposta corretta, questo ha lo svantaggio di aggiungere un compito e uno se su ogni chiamata di funzione e aggiungere un membro '_statics' alla funzione, tuttavia ci sono alcuni vantaggi: gli argomenti sono lì a la parte superiore non nella funzione interna, usando un 'statico' nel codice della funzione interna è esplicita con un '_s.' prefisso, ed è nel complesso più semplice da guardare e comprendere.


1

Sommario:

In ES6/ ES 2015 la classparola chiave è stata introdotta con una staticparola chiave accompagnata . Tieni presente che questo è zucchero sintattico rispetto al modello di eredità prototipo che javavscript incarna. La staticparola chiave funziona nel modo seguente per i metodi:

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);


2
Stava chiedendo una variabile statica, non una funzione statica.
Konrad Höffner,

1

Ho usato il prototipo e in questo modo ha funzionato:

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

Cat.COLLECTION_NAME = "cats";

o usando un getter statico:

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

  static get COLLECTION_NAME() {
    return "cats"
  }
}

0

Le variabili a livello di finestra sono una specie di statica, nel senso che puoi usare il riferimento diretto e sono disponibili per tutte le parti della tua app


3
Una descrizione molto migliore di tali variabili è "globale", piuttosto che statica.
Patrick M,

0

Non esiste una variabile statica in Javascript. Questo linguaggio è orientato agli oggetti basato su prototipo, quindi non ci sono classi, ma prototipi da cui gli oggetti "copiano" se stessi.

Puoi simularli con variabili globali o con la prototipazione (aggiungendo una proprietà al prototipo):

function circle(){
}
circle.prototype.pi=3.14159

Questo metodo funziona, ma stai inquinando ilFunction.prototype
Dan

@Dan: ho capito che questo sarebbe solo per il cerchio e non per la funzione. Almeno questo è ciò che Chrome cerca di dirmi: function circle() {}| circle.prototype| circle.prototype.pi = 3.14| circle.prototype| Function.prototype| Function.__proto__(se questo è ciò che intendevi)
Aktau,

0

Lavorando con i siti Web MVC che utilizzano jQuery, mi piace assicurarmi che le azioni AJAX all'interno di determinati gestori di eventi possano essere eseguite solo una volta completata la richiesta precedente. Per raggiungere questo obiettivo utilizzo una variabile oggetto jqXHR "statica".

Dato il seguente pulsante:

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

In genere utilizzo un IIFE come questo per il mio gestore di clic:

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);

0

Se vuoi usare il prototipo, allora c'è un modo

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);

In questo modo sarai in grado di accedere alla variabile contatore da qualsiasi istanza e qualsiasi cambiamento nella proprietà verrà immediatamente riflesso !!

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.