Statische Variablen in JavaScript


716

Wie kann ich statische Variablen in Javascript erstellen?


Wir können label oder ein anderes HTML-Tag mit dem Stilattribut "dispaly: none" definieren und den Variablenwert für diesen Wert und die Operation für diesen Wert festlegen. Lass es uns nicht schwer nehmen.
Asghar

Die einfachste Lösung, die ich gefunden habe: Definieren Sie überhaupt keine statische Variable in der Klasse. Wenn Sie eine statische Variable verwenden möchten, definieren Sie sie einfach dort und dann, z someFunc = () => { MyClass.myStaticVariable = 1; }. Erstellen Sie dann einfach eine statische Methode, um das statische Element zurückzugeben, z static getStatic() { return MyClass.myStaticVariable; }. Dann können Sie einfach MyClass.getStatic()von außerhalb der Klasse anrufen , um die statischen Daten zu erhalten!
Pixel

Antworten:


863

Wenn Sie aus einer klassenbasierten, statisch typisierten objektorientierten Sprache stammen (wie Java, C ++ oder C #) gehen Sie davon aus, dass Sie versuchen, eine Variable oder Methode zu erstellen, die einem "Typ" zugeordnet ist, jedoch keiner Instanz.

Ein Beispiel mit einem "klassischen" Ansatz mit Konstruktorfunktionen könnte Ihnen möglicherweise dabei helfen, die Konzepte von grundlegendem OO-JavaScript zu verstehen:

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

staticPropertywird im MyClass-Objekt (das eine Funktion ist) definiert und hat nichts mit den erstellten Instanzen zu tun. JavaScript behandelt Funktionen als erstklassige Objekte . Als Objekt können Sie einer Funktion also Eigenschaften zuweisen.

UPDATE: ES6 hat die Möglichkeit eingeführt , Klassen über das zu deklarierenclass Schlüsselwort . Es ist Syntaxzucker über der vorhandenen prototypbasierten Vererbung.

Das staticSchlüsselwort können Sie auf einfache Weise statische Eigenschaften oder Methoden in einer Klasse definieren.

Sehen wir uns das obige Beispiel an, das mit ES6-Klassen implementiert wurde:

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
Vermutlich privilegedMethodentspricht dies nicht einer privaten Methode in OO, da es den Anschein hat, als könnte es auf einer Instanz von MyClass aufgerufen werden? Meinst du, es ist privilegiert, weil es zugreifen kann privateVariable?
Dónal

3
Kann nicht verwendet this.constructorwerden, um über "Instanzmethoden" auf die statischen Variablen zuzugreifen? Wenn ja, lohnt es sich, es der Antwort hinzuzufügen.
Ciro Santilli 法轮功 病毒 审查 六四 事件 22

1
Sie können in Ihrem Beispiel auch statische Funktionen erwähnen .
David Rodrigues

18
Hallo, ich bin nicht sicher, ob ich mit dieser Zeile einverstanden bin. // Statische Variable, die von allen Instanzen gemeinsam genutzt wird. 'MyClass.staticProperty = "baz";' Für mich bedeutet dies , dass Sie baz aus 'myInstance.staticProperty' finden können, was Sie natürlich nicht können.
Fullstacklife

5
Vielleicht sollte es lesen MyClass.prototype.staticProperty = "baz";oder noch korrekter zu OO-Prinzipien sein, die statische Eigenschaft sollte tatsächlich als anonyme Funktion definiert MyClass.prototype.staticProperty = function () {return staticVar;}werden, damit alle Instanzen auf eine einzelne Variable zugreifen, die auch mit einem Setter geändert werden kann.
Lindsaymacvean

535

Sie können die Tatsache ausnutzen, dass JS-Funktionen auch Objekte sind - was bedeutet, dass sie Eigenschaften haben können.

Beispiel: Zitieren Sie das Beispiel aus dem (jetzt verschwundenen) Artikel Statische Variablen 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);
}

Wenn Sie diese Funktion mehrmals aufrufen, wird der Zähler erhöht.

Und dies ist wahrscheinlich eine viel bessere Lösung, als den globalen Namespace mit einer globalen Variablen zu polieren.


Und hier ist eine andere mögliche Lösung, die auf einem Abschluss basiert: Trick, statische Variablen in Javascript zu verwenden :

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.

Damit erhalten Sie die gleiche Art von Ergebnis - außer dass diesmal der inkrementierte Wert zurückgegeben wird, anstatt angezeigt zu werden.


50
Als Abkürzung können Sie nur tun, countMyself.counter = countMyself.counter || initial_value;wenn die statische Variable niemals falsch sein wird (false, 0, null oder leere Zeichenfolge)
Kip

3
Etwas kürzer und klarer: (function () {var id = 0; function uniqueID () {return id ++;};}) ();
Tom Robinson

3
Der Zähler beim Schließen ist sehr schnell als in der Klasse in Firefox. jsperf.com/static-counter-in-class-vs-in-closure
Sony Santos

Verwenden Sie ===für typeofSchecks, sonst bekommen Sie einen seltsamen Zwang.
Tau

@SonySantos Ihr Test zeigt das Gegenteil für Firefox 40
bartolo-otrit

96

Sie tun dies über ein IIFE (sofort aufgerufener Funktionsausdruck):

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

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

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

21
Ich würde sagen, dies ist der idiomatischste Weg, dies in JavaScript zu tun. Schade, dass es dank anderer Methoden, die für Leute aus anderen Sprachen wahrscheinlich schmackhafter sind, nicht zu viele positive Stimmen bekommt.

1
Ich würde "Closure" anstatt nur "IIFE" umformulieren.
Zendka

39

Sie können argument.callee verwenden, um "statische" Variablen zu speichern (dies ist auch in anonymen Funktionen nützlich):

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

3
Soweit ich verstehen kann, hat diese Methode einen (nur einen?) Vorteil gegenüber Pascal MARTIN: Sie können sie für anonyme Funktionen verwenden. Ein Beispiel dafür wäre großartig
Dan

27
arguments.calleeist veraltet.
Quolonel Fragen

Ich habe JS die ganze Zeit ziemlich lächerlich gemacht, aber es calleeschien mir eine nette Sache zu sein. Ich frage mich, warum der Hack sie beschlossen hat, dies zu verwerfen ...: |
user2173353

35

Ich habe ein paar ähnliche Antworten gesehen, aber ich möchte diesen Beitrag erwähnen es am besten beschreibt, also möchte ich es mit Ihnen teilen.

Hier ist ein Code, den ich geändert habe, um ein vollständiges Beispiel zu erhalten, das hoffentlich der Community zugute kommt, da es als Entwurfsvorlage für Klassen verwendet werden kann.

Es beantwortet auch Ihre Frage:

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

In diesem Beispiel können Sie wie folgt auf die statischen Eigenschaften / Funktionen zugreifen :

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

Und die Objekteigenschaften / funktionieren einfach wie folgt:

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

Beachten Sie, dass in podcast.immutableProp () ein Abschluss vorliegt : Der Verweis auf _somePrivateVariable bleibt in der Funktion erhalten.

Sie können sogar Getter und Setter definieren . Schauen Sie sich dieses Code-Snippet an (wo dsich der Prototyp des Objekts befindet, für den Sie eine Eigenschaft deklarieren möchten, yist eine private Variable, die außerhalb des Konstruktors nicht sichtbar ist):

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

Es definiert die Eigenschaft d.yearüber getund setFunktionen - wenn Sie nichts angeben set, ist die Eigenschaft schreibgeschützt und kann nicht geändert werden (beachten Sie, dass Sie keine Fehlermeldung erhalten, wenn Sie versuchen, sie festzulegen , dies hat jedoch keine Auswirkungen). Jede Eigenschaft hat die Attribute writable, configurable(lassen Änderung nach Anmeldung) und enumerable(lassen Sie es als Aufzählungs verwenden), die standardmäßig sind false. Sie können sie über definePropertyim 3. Parameter einstellen , z enumerable: true.

Was auch gültig ist, ist diese Syntax:

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

aDies definiert eine lesbare / beschreibbare Eigenschaft , eine schreibgeschützte Eigenschaft bund eine schreibgeschützte Eigenschaft c, über die auf die Eigenschaft azugegriffen werden kann.

Verwendungszweck:

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

Anmerkungen:

Um unerwartetes Verhalten zu vermeiden, falls Sie das newSchlüsselwort vergessen haben , sollten Sie der Funktion Folgendes hinzufügen Podcast:

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

Jetzt funktionieren beide der folgenden Instanziierungen wie erwartet:

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

Die 'neue' Anweisung erstellt ein neues Objekt und kopiert alle Eigenschaften und Methoden, d. H.

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"

Beachten Sie auch, dass es in einigen Situationen nützlich sein kann, die returnAnweisung in der Konstruktorfunktion Podcastzu verwenden, um benutzerdefinierte Objektschutzfunktionen zurückzugeben, auf die sich die Klasse intern stützt, die jedoch verfügbar gemacht werden müssen. Dies wird in Kapitel 2 (Objekte) der Artikelserie näher erläutert.

Das kann man sagen aund berben von Podcast. Was ist nun, wenn Sie Podcast eine Methode hinzufügen möchten, die für alle nach aund bnach der Instanziierung gilt? Verwenden Sie in diesem Fall .prototypeFolgendes:

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

Rufen Sie jetzt an aund noch beinmal:

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

Weitere Details zu Prototypen finden Sie hier . Wenn Sie mehr Vererbung vornehmen möchten, schlage ich vor, dies zu prüfen .


Es wird dringend empfohlen , die oben erwähnten Artikelserien zu lesen. Sie enthalten auch die folgenden Themen:

  1. Funktionen
  2. Objekte
  3. Prototypen
  4. Durchsetzen neuer Konstruktorfunktionen
  5. Heben
  6. Automatisches Einfügen von Semikolons
  7. Statische Eigenschaften und Methoden

Beachten Sie, dass das automatische Einfügen von Semikolons in JavaScript (wie in Abschnitt 6 erwähnt) sehr häufig für seltsame Probleme in Ihrem Code verantwortlich ist. Daher würde ich es eher als Fehler als als Feature betrachten.

Wenn Sie mehr lesen möchten, finden Sie hier einen interessanten MSDN-Artikel zu diesen Themen. Einige der dort beschriebenen Artikel enthalten noch mehr Details.

Was ist interessant zu lesen , wie gut (auch die Themen abdeckt wie oben erwähnt) sind die Artikel aus dem MDN JavaScript - Führer :

Wenn Sie wissen möchten, wie man c # out-Parameter (wie in DateTime.TryParse(str, out result)) in JavaScript emuliert , finden Sie hier Beispielcode.


Diejenigen unter Ihnen, die mit dem Internet Explorer arbeiten (der keine Konsole für JavaScript hat, es sei denn, Sie öffnen die Entwicklertools mit F12und öffnen die Registerkarte "Konsole"), finden das folgende Snippet möglicherweise hilfreich. Es ermöglicht Ihnen die Verwendung console.log(msg);wie in den obigen Beispielen verwendet. Fügen Sie es einfach vor der PodcastFunktion ein.

Hier ist der Code oben in einem vollständigen Code-Snippet:


Anmerkungen:

  • Einige gute Tipps, Hinweise und Empfehlungen zur JavaScript-Programmierung im Allgemeinen finden Sie hier (Best Practices für JavaScript) und dort ('var' versus 'let') . Empfehlenswert ist auch dieser Artikel über implizite Typografien (Zwang) .

  • Eine bequeme Möglichkeit, Klassen zu verwenden und sie in JavaScript zu kompilieren, ist TypeScript. Hier ist ein Spielplatz, auf dem Sie einige Beispiele finden, die Ihnen zeigen, wie es funktioniert. Auch wenn Sie momentan kein TypeScript verwenden, können Sie einen Blick darauf werfen, da Sie TypeScript nebeneinander mit dem JavaScript-Ergebnis vergleichen können. Die meisten Beispiele sind einfach, aber es gibt auch ein Raytracer-Beispiel, das Sie sofort ausprobieren können. Ich empfehle, besonders die Beispiele "Verwenden von Klassen", "Verwenden von Vererbung" und "Verwenden von Generika" zu betrachten, indem Sie sie in der Combobox auswählen - dies sind nette Vorlagen, die Sie sofort in JavaScript verwenden können. Typoskript wird mit Angular verwendet.

  • Um die Kapselung lokaler Variablen, Funktionen usw. in JavaScript zu erreichen, empfehle ich, ein Muster wie das folgende zu verwenden (JQuery verwendet dieselbe Technik):

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

Natürlich können und sollten Sie den Skriptcode in einer separaten *.jsDatei ablegen. Dies wird nur inline geschrieben, um das Beispiel kurz zu halten.

Selbstaufrufende Funktionen (auch bekannt als IIFE = Sofort aufgerufener Funktionsausdruck) werden hier ausführlicher beschrieben .


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

Aktualisierte Antwort:

In ECMAScript 6 können Sie statische Funktionen mit dem staticSchlüsselwort erstellen :

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

ES6-Klassen führen keine neue Semantik für die Statik ein. In ES5 können Sie dasselbe wie folgt tun:

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

Sie können einer Eigenschaft von zuweisen, Fooda in JavaScript Funktionen Objekte sind.


Foo.bar;Gibt die ihm zugewiesene Funktion zurück, nicht die von der Funktion zurückgegebene Zeichenfolge, wie Ihr Kommentar impliziert.

Können Sie in beiden Beispielen einige Informationen zum Festlegen (Überschreiben) eines statischen Werts hinzufügen?
Wilt

1
@Wilt In beiden Fällen ist eine "statische" Eigenschaft nur eine Eigenschaft der Funktion. Sie legen sie also fest und überschreiben sie wie jede andere Eigenschaft in JavaScript. In beiden Fällen können Sie die Set - barEigenschaft Fooauf 3diese mag:Foo.bar = 3;
Max Heiber


16

Das folgende Beispiel und die folgende Erklärung stammen aus dem Buch Professional JavaScript for Web Developers 2nd Edition von Nicholas Zakas. Dies ist die Antwort, nach der ich gesucht habe, daher dachte ich, es wäre hilfreich, sie hier hinzuzufügen.

(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

Der PersonKonstruktor in diesem Beispiel hat Zugriff auf den Namen der privaten Variablen, ebenso wie die Methoden getName()und setName(). Bei Verwendung dieses Musters wird die Namensvariable statisch und wird in allen Instanzen verwendet. Dies bedeutet, dass der Aufruf setName()einer Instanz alle anderen Instanzen betrifft. Durch Aufrufen setName()oder Erstellen einer neuen PersonInstanz wird die Namensvariable auf einen neuen Wert gesetzt. Dies führt dazu, dass alle Instanzen denselben Wert zurückgeben.


sieht Konstruktor + Prototyp (Hybrid)
Ganesh Kumar

2
Dadurch wird das Person-Objekt in den globalen Namespace eingefügt. Keine Lösung, die ich empfehlen würde.
Ghola

Ich denke nicht, dass dies eine echte statische Variable ist, da sie bei jedem neuen Objekt anders instanziiert wird. Ein statisches Objekt sollte über alle Objekte hinweg konsistent sein, die vom übergeordneten Prototyp erben.
Lindsaymacvean

1
@Ghola Hier sollte erklärt werden, wie eine statische Variable erstellt wird. Der richtige Namespace und das Vermeiden von Globals ist ein separates Thema, das möglicherweise zur Komplexität der Antwort beigetragen hat. Es ist Sache des Benutzers, zu bestimmen, wie der Konstruktor ohne Verschmutzung angehängt werden soll. Wenn es für Nicholas Zakas gut genug ist, ist es für mich gut genug.
Nate

@lindsaymacvean Es ist eine statische Variable, da der einzelne Wert von allen Instanzen gemeinsam genutzt wird. Es ist in Ordnung, wenn sich der Wert ändert. Wenn eine Instanz den Wert ändert, sind alle Instanzen betroffen. Es ist unwahrscheinlich, dass es genauso verwendet wird wie im obigen Beispiel. Das Zulassen, dass der Wert während der Instanziierung festgelegt wird, soll nur zeigen, dass dies möglich ist. Ein wahrscheinlicherer Anwendungsfall wäre, nur den Getter und den Setter zu haben oder zumindest zu überprüfen, ob er auf etwas anderes als undefiniert gesetzt ist.
Nate

15

Wenn Sie die neue Klassensyntax verwenden , können Sie jetzt Folgendes tun:

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

    console.log(MyClass.myStaticVariable);

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

Dadurch wird effektiv eine statische Variable in JavaScript erstellt.


Dies ist nützlich, wenn statische Dienstprogrammklassen erstellt werden!
Indolering

1
Jetzt stellt sich die Frage, wie Sie einen Wert beibehalten und mit einem Setter Änderungen daran zulassen können. Ein Abschluss wäre erforderlich oder eine Eigenschaft MyClassaußerhalb des Klassenkonstrukts definiert.
Trincot


8

Wenn Sie statische Variablen zum Erstellen von Konstanten in Ihrer Anwendung deklarieren möchten, habe ich Folgendes als einfachsten Ansatz empfunden

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

Über das classvon ECMAScript 2015 eingeführte. Die anderen Antworten sind nicht ganz klar.

Hier ist ein Beispiel, das zeigt, wie eine statische Variable staticVarmit dem erstellt wird 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

Für den Zugriff auf die statische Variable verwenden wir die .constructorEigenschaft, die einen Verweis auf die Objektkonstruktorfunktion zurückgibt, mit der die Klasse erstellt wurde. Wir können es auf den beiden erstellten Instanzen aufrufen:

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

Es gibt andere ähnliche Antworten, aber keine davon hat mich wirklich angesprochen. Folgendes habe ich erreicht:

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

7

Darüber hinaus gibt es derzeit einen Entwurf ( Vorschlag der Stufe 2 ) zu ECMA-Vorschlägen , in dem static öffentliche Felder in Klassen eingeführt werden. ( private Felder wurden berücksichtigt )

Anhand des Beispiels aus dem Vorschlag staticsieht die vorgeschlagene Syntax folgendermaßen aus:

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

und äquivalent zu den folgenden sein, die andere hervorgehoben haben:

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

Sie können dann über darauf zugreifen CustomDate.epoch.

Sie können den neuen Vorschlag in verfolgen proposal-static-class-features.


Derzeit unterstützt babel diese Funktion mit dem Plugin für Eigenschaften von Transformationsklassen, das Sie verwenden können. Darüber hinaus V8wird es implementiert , obwohl es noch in Bearbeitung ist .


6

Sie können eine statische Variable in JavaScript wie folgt erstellen. Hier countist die statische Variable.

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

Sie können der statischen Variablen entweder mit der PersonFunktion oder mit einer der folgenden Instanzen Werte zuweisen :

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

Dies ist einer der guten Ansätze, um statische Variablen zu deklarieren und in JavaScript darauf zuzugreifen.
ArunDhwaj IIITH

5

Wenn Sie eine globale statische Variable erstellen möchten:

var my_id = 123;

Ersetzen Sie die Variable durch die folgende:

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

4

Das, was einer statischen Variablen in JavaScript am nächsten kommt, ist eine globale Variable - dies ist einfach eine Variable, die außerhalb des Bereichs eines Funktions- oder Objektliteral deklariert ist:

var thisIsGlobal = 1;

function foo() {
    var thisIsNot = 2;
}

Das andere, was Sie tun könnten, wäre, globale Variablen in einem Objektliteral wie folgt zu speichern:

var foo = { bar : 1 }

Und dann auf die Variablen wie folgt zugreifen : foo.bar.


Dieser hat mir geholfen, mehrere Dateien hochzuladen ..... var foo = {counter: 1}; Funktion moreFiles () {fileName = "File" + foo.counter; foo.counter = foo.counter + 1;
veer7

4

Testen Sie Folgendes, um alle Klassenkonzepte hier zu verdichten:

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

Eine andere Möglichkeit, sich mit Best Practices in diesen Dingen zu befassen, besteht darin, zu sehen, wie Coffeescript diese Konzepte übersetzt.

#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 sind Variablen standardmäßig statisch . Beispiel :

var x = 0;

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

setInterval(draw, 1000);

Der Wert von x wird alle 1000 Millisekunden um 1 erhöht.
Es wird 1,2,3 usw. gedruckt


2
Das ist ein anderer Fall. In Ihrem Beispiel geht es um Bereiche.
Challet

4

Es gibt einen anderen Ansatz, der meine Anforderungen nach dem Durchsuchen dieses Threads gelöst hat. Es kommt genau darauf an, was Sie mit einer "statischen Variablen" erreichen wollen.

Mit der globalen Eigenschaft sessionStorage oder localStorage können Daten für die Dauer der Sitzung oder für einen unbestimmten längeren Zeitraum gespeichert werden, bis sie explizit gelöscht werden. Dies ermöglicht die gemeinsame Nutzung von Daten zwischen allen Fenstern, Frames, Registerkarten, Popups usw. Ihrer Seite / App und ist viel leistungsfähiger als eine einfache "statische / globale Variable" in einem Codesegment.

Es vermeidet jeglichen Ärger mit dem Umfang, der Lebensdauer, der Semantik, der Dynamik usw. globaler Variablen der obersten Ebene, dh Window.myglobal. Ich weiß nicht, wie effizient es ist, aber das ist nicht wichtig für bescheidene Datenmengen, auf die mit bescheidenen Raten zugegriffen wird.

Einfach als "sessionStorage.mydata = irgendetwas" zugegriffen und auf ähnliche Weise abgerufen. Siehe "JavaScript: The Definitive Guide, Sechste Ausgabe", David Flanagan, ISBN: 978-0-596-80552-4, Kapitel 20, Abschnitt 20.1. Dies kann einfach als PDF durch einfache Suche oder in Ihrem O'Reilly Safaribooks-Abonnement (Gold wert) heruntergeladen werden.


2

Funktionen / Klassen erlauben nur einen Konstruktor für ihren Objektbereich. Function Hoisting, declarations & expressions

  • Mit dem Funktionskonstruktor erstellte Funktionen erstellen keine Abschlüsse für ihre Erstellungskontexte. Sie werden immer im globalen Bereich erstellt.

      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)

Verschlüsse - Verschlusskopien funktionieren mit erhaltenen Daten.

  • Die Kopien jedes Abschlusses werden zu einer Funktion mit eigenen freien Werten oder Referenzen erstellt. Immer wenn Sie eine Funktion in einer anderen Funktion verwenden, wird ein Abschluss verwendet.
  • Ein Abschluss in JavaScript entspricht dem Verwalten einer Kopie aller lokalen Variablen der übergeordneten Funktion durch die 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

ES5-Funktionsklassen : Verwendet Object.defineProperty (O, P, Attribute)

Die Object.defineProperty () -Methode definiert eine neue Eigenschaft direkt für ein Objekt oder ändert eine vorhandene Eigenschaft für ein Objekt und gibt das Objekt zurück.

Erstellt einige Methoden mit `` , damit jeder die Funktionsklassen leicht verstehen kann.

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

Das folgende Code-Snippet dient zum Testen. Jede Instanz verfügt über eine eigene Kopie von Instanzmitgliedern und allgemeinen statischen Mitgliedern.

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

Statische Methodenaufrufe werden direkt in der Klasse ausgeführt und können in Instanzen der Klasse nicht aufgerufen werden. Sie können die Aufrufe für statische Mitglieder jedoch innerhalb einer Instanz ausführen.

Syntax verwenden:

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

ES6-Klassen: ES2015-Klassen sind ein einfacher Zucker über dem prototypbasierten OO-Muster. Ein einziges praktisches deklaratives Formular erleichtert die Verwendung von Klassenmustern und fördert die Interoperabilität. Klassen unterstützen prototypbasierte Vererbung, Superaufrufe, Instanz- und statische Methoden und Konstruktoren.

Beispiel : siehe meinen vorherigen Beitrag.


2

Es gibt 4 Möglichkeiten, funktionslokale statische Variablen in Javascript zu emulieren.

Methode 1: Verwenden von Eigenschaften von Funktionsobjekten (wird in alten Browsern unterstützt)

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

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

Methode 2: Verwenden eines Verschlusses, Variante 1 (wird in alten Browsern unterstützt)

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

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

Methode 3: Verwenden eines Verschlusses, Variante 2 (wird auch in alten Browsern unterstützt)

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

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

Methode 4: Verwenden eines Verschlusses, Variante 3 (erfordert Unterstützung für EcmaScript 2015)

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

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

2

Sie können statische Funktionen in JavaScript mit dem staticSchlüsselwort definieren:

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

MyClass.myStaticFunction(); // 42

Zum jetzigen Zeitpunkt können Sie noch keine statischen Eigenschaften (außer Funktionen) innerhalb der Klasse definieren. Statische Eigenschaften sind immer noch ein Vorschlag der Stufe 3 , was bedeutet, dass sie noch nicht Teil von JavaScript sind. Nichts hindert Sie jedoch daran, einfach einer Klasse zuzuweisen, wie Sie es bei jedem anderen Objekt tun würden:

class MyClass {}

MyClass.myStaticProperty = 42;

MyClass.myStaticProperty; // 42

Schlussbemerkung: Seien Sie vorsichtig bei der Verwendung statischer Objekte mit Vererbung. Alle geerbten Klassen verwenden dieselbe Kopie des Objekts .


1

In JavaScript gibt es keinen statischen Begriff oder ein statisches Schlüsselwort, aber wir können solche Daten direkt in ein Funktionsobjekt einfügen (wie in jedem anderen Objekt).

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

Ich benutze häufig statische Funktionsvariablen und es ist wirklich schade, dass JS dafür keinen eingebauten Mechanismus hat. Zu oft sehe ich Code, in dem Variablen und Funktionen in einem äußeren Bereich definiert sind, obwohl sie nur in einer Funktion verwendet werden. Das ist hässlich, fehleranfällig und bittet nur um Ärger ...

Ich habe mir folgende Methode ausgedacht:

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

Dies fügt allen Funktionen eine 'statische' Methode hinzu (ja, entspannen Sie sich einfach). Wenn sie aufgerufen wird, fügt sie dem Funktionsobjekt ein leeres Objekt (_statics) hinzu und gibt es zurück. Wenn eine Init-Funktion bereitgestellt wird, wird _statics auf init () result gesetzt.

Sie können dann tun:

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

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

Wenn man dies mit einem IIFE vergleicht, das die andere richtige Antwort ist, hat dies den Nachteil, dass bei jedem Funktionsaufruf eine Zuweisung und eine hinzugefügt wird, wenn der Funktion ein '_statics'-Mitglied hinzugefügt wird. Es gibt jedoch einige Vorteile: Die Argumente sind da bei Das oberste nicht in der internen Funktion, die Verwendung eines 'statischen' im internen Funktionscode ist explizit mit einem '_s'. Präfix, und es ist insgesamt einfacher zu betrachten und zu verstehen.


1

Zusammenfassung:

In ES6/ ES 2015 wurde das classSchlüsselwort mit einem begleitenden staticSchlüsselwort eingeführt. Denken Sie daran, dass dies syntaktischer Zucker gegenüber dem prototypischen Vererbungsmodell ist, das Javavscript verkörpert. Das staticSchlüsselwort funktioniert für Methoden folgendermaßen:

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
Er fragte nach einer statischen Variablen, nicht nach einer statischen Funktion.
Konrad Höffner

1

Ich habe den Prototyp verwendet und so hat es funktioniert:

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

Cat.COLLECTION_NAME = "cats";

oder mit einem statischen Getter:

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

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

0

Vars auf Fensterebene sind in dem Sinne statisch, dass Sie eine direkte Referenz verwenden können und diese für alle Teile Ihrer App verfügbar sind


3
Eine viel bessere Beschreibung solcher Variablen ist "global" und nicht statisch.
Patrick M

0

In Javascript gibt es keine statische Variable. Diese Sprache ist prototypbasiert objektorientiert, daher gibt es keine Klassen, sondern Prototypen, von denen Objekte sich selbst "kopieren".

Sie können sie mit globalen Variablen oder mit Prototyping simulieren (dem Prototyp eine Eigenschaft hinzufügen):

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

Diese Methode funktioniert, aber Sie verschmutzen dieFunction.prototype
Dan

@ Dan: Ich verstehe, dass dies nur für den Kreis und nicht für die Funktion ist. Zumindest versucht Chrome mir das zu sagen: function circle() {}| circle.prototype| circle.prototype.pi = 3.14| circle.prototype| Function.prototype| Function.__proto__(Wenn Sie das gemeint haben)
Aktau

0

Bei der Arbeit mit MVC-Websites, die jQuery verwenden, möchte ich sicherstellen, dass AJAX-Aktionen in bestimmten Ereignishandlern erst ausgeführt werden können, wenn die vorherige Anforderung abgeschlossen wurde. Ich benutze eine "statische" jqXHR-Objektvariable, um dies zu erreichen.

Gegeben die folgende Schaltfläche:

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

Im Allgemeinen verwende ich ein solches IIFE für meinen Klick-Handler:

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

Wenn Sie einen Prototyp verwenden möchten, gibt es einen Weg

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

Auf diese Weise können Sie von jeder Instanz aus auf die Zählervariable zugreifen und jede Änderung der Eigenschaft wird sofort wiedergegeben !!

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.