Zmienne statyczne w JavaScript


716

Jak mogę tworzyć zmienne statyczne w JavaScript?


możemy zdefiniować etykietę lub inny znacznik html za pomocą atrybutu stylu „dispaly: none” i ustawić wartość zmiennej dla tej wartości oraz działanie na tej wartości. Nie trudźmy się.
asghar

Najprostsze rozwiązanie, jakie znalazłem: w ogóle nie definiuj zmiennej statycznej w klasie. Jeśli chcesz użyć zmiennej statycznej, po prostu ją zdefiniuj, a następnie np someFunc = () => { MyClass.myStaticVariable = 1; }. Następnie po prostu utwórz metodę statyczną, aby zwrócić element statyczny, np static getStatic() { return MyClass.myStaticVariable; }. Następnie możesz po prostu zadzwonić MyClass.getStatic()spoza klasy, aby uzyskać dane statyczne!
Piksel

Odpowiedzi:


863

Jeśli pochodzisz z opartego na klasach, statycznie typowanego języka obiektowego (takiego jak Java, C ++ lub C #) , zakładam, że próbujesz utworzyć zmienną lub metodę powiązaną z „typem”, ale nie z instancją.

Przykład zastosowania „klasycznego” podejścia z funkcjami konstruktora może pomóc w zrozumieniu podstawowych pojęć 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();

staticPropertyjest zdefiniowany w obiekcie MyClass (który jest funkcją) i nie ma nic wspólnego z utworzonymi instancjami, JavaScript traktuje funkcje jak obiekty pierwszej klasy , więc będąc obiektem, możesz przypisywać właściwości do funkcji.

AKTUALIZACJA: ES6 wprowadził możliwość deklarowania klas za pomocą classsłowa kluczowego. Jest to cukier składniowy w stosunku do istniejącego dziedziczenia opartego na prototypach.

Słowo statickluczowe pozwala łatwo zdefiniować właściwości lub metody statyczne w klasie.

Zobaczmy powyższy przykład zaimplementowany z klasami 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
Przypuszczalnie privilegedMethodnie jest to odpowiednik prywatnej metody w OO, ponieważ wygląda na to, że można ją wywołać na instancji MyClass? Czy masz na myśli, że jest uprzywilejowany, ponieważ ma dostęp privateVariable?
Dónal

3
Nie this.constructormożna użyć do uzyskania dostępu do zmiennych statycznych z „metod instancji”? Jeśli tak, warto dodać to do odpowiedzi.
Ciro Santilli 22 病毒 审查 六四 事件 法轮功 法轮功

1
Możesz również wspomnieć o funkcjach statycznych w swoim przykładzie.
David Rodrigues

18
cześć, nie jestem pewien, czy zgadzam się z tą linią // Zmienna statyczna wspólna dla wszystkich instancji „MyClass.staticProperty =" baz "; ' co do mnie, że wnioskuje, że można znaleźć baz z „myInstance.staticProperty”, czego oczywiście nie można.
fullstacklife

5
Być może powinien on czytać MyClass.prototype.staticProperty = "baz";lub być jeszcze bardziej zgodny z zasadami OO, właściwość statyczna powinna być faktycznie zdefiniowana jako funkcja anonimowa, MyClass.prototype.staticProperty = function () {return staticVar;}tak aby wszystkie instancje miały dostęp do jednej zmiennej, którą można również zmienić za pomocą settera.
Lindsaymacvean,

535

Możesz skorzystać z faktu, że funkcje JS są również obiektami - co oznacza, że ​​mogą mieć właściwości.

Na przykład, cytując przykład podany w (już nieistniejącym) artykule Zmienne statyczne w 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);
}

Jeśli wywołasz tę funkcję kilka razy, zobaczysz, że licznik jest zwiększany.

Jest to prawdopodobnie o wiele lepsze rozwiązanie niż przeszukiwanie globalnej przestrzeni nazw za pomocą zmiennej globalnej.


A oto inne możliwe rozwiązanie oparte na zamknięciu: Sztuczka, aby użyć zmiennych statycznych w 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.

Co daje ci ten sam wynik - z tym wyjątkiem, że zamiast tego wyświetlana jest wartość przyrostowa.


50
jako skrót, możesz po prostu zrobić, countMyself.counter = countMyself.counter || initial_value;jeśli zmienna statyczna nigdy nie będzie falsey (false, 0, null lub pusty ciąg)
Kip

3
Nieco krótszy i jaśniejszy: (function () {var id = 0; function uniqueID () {return id ++;};}) ();
Tom Robinson,

3
Licznik w zamknięciu jest znacznie szybszy niż w klasie w Firefoksie. jsperf.com/static-counter-in-class-vs-in-closure
Sony Santos

Skorzystaj ===z typeofczeków, bo będziesz miał dziwny przymus.
dewd

@ SonySantos Twój test pokazuje coś przeciwnego dla Firefoksa 40
bartolo-otrit,

96

Robisz to poprzez IIFE (natychmiast wywołane wyrażenie funkcji):

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

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

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

21
Powiedziałbym, że jest to najbardziej idiomatyczny sposób na zrobienie tego w JavaScript. Szkoda, że ​​nie ma zbyt wielu pozytywnych opinii dzięki innym metodom, które prawdopodobnie są bardziej smaczne dla ludzi pochodzących z innych języków.

1
Przeformułowałbym używając „zamknięcia” zamiast tylko „IIFE”.
zendka

39

możesz użyć arguments.callee do przechowywania zmiennych „statycznych” (jest to również przydatne w funkcji anonimowej):

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

3
O ile rozumiem, ta metoda ma jedną (tylko jedną?) Przewagę nad sposobem Pascala MARTINA: możesz jej użyć do anonimowych funkcji. Przykład tego byłby świetny
Dan

27
arguments.calleejest przestarzałe.
Pytania do Kwolonela,

Przez cały czas wyśmiewałam JS, ale calleewydawało mi się, że to miło. Zastanawiam się, dlaczego hack postanowili wycofać to ...: |
user2173353,

35

Widziałem kilka podobnych odpowiedzi, ale chciałbym wspomnieć, że ten post najlepiej to opisuje, więc chciałbym się z tobą podzielić.

Oto pobrany z niego kod, który zmodyfikowałem, aby uzyskać kompletny przykład, który, mam nadzieję, daje korzyść społeczności, ponieważ można go użyć jako szablonu projektu dla klas.

Odpowiada również na twoje pytanie:

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

Biorąc pod uwagę ten przykład, możesz uzyskać dostęp do właściwości / funkcji statycznej w następujący sposób:

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

A właściwości / funkcje obiektu po prostu jako:

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

Zauważ, że w podcast.immutableProp () mamy zamknięcie : Odwołanie do _somePrivateVariable jest przechowywane wewnątrz funkcji.

Możesz nawet zdefiniować obiekty pobierające i ustawiające . Spójrz na ten fragment kodu (gdzie djest prototyp obiektu, dla którego chcesz zadeklarować właściwość, yto zmienna prywatna niewidoczna poza konstruktorem):

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

Definiuje właściwość d.yearpoprzez geti setfunkcje - jeśli nie określisz set, właściwość jest tylko do odczytu i nie można jej modyfikować (pamiętaj, że nie pojawi się błąd, jeśli spróbujesz ją ustawić, ale nie da to efektu). Każda nieruchomość ma atrybuty writable, configurable(pozwala na zmianę po zgłoszeniu) i enumerable(pozwalają na zastosowanie go jako wyliczający), które są domyślnie false. Możesz ustawić je za definePropertypomocą trzeciego parametru, np enumerable: true.

Prawidłowa jest również następująca składnia:

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

która definiuje właściwość do odczytu / zapisu, właściwość atylko do odczytu bi właściwość tylko do zapisu c, za pośrednictwem której amożna uzyskać dostęp do właściwości .

Stosowanie:

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

Uwagi:

Aby uniknąć nieoczekiwanego zachowania w przypadku zapomnienia newsłowa kluczowego, sugeruję dodanie do funkcji następujących elementów Podcast:

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

Teraz obie następujące instancje będą działać zgodnie z oczekiwaniami:

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

Instrukcja „new” tworzy nowy obiekt i kopiuje wszystkie właściwości i metody, tj

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"

Należy również zauważyć, że w niektórych sytuacjach użyteczne może być użycie returninstrukcji w funkcji konstruktora, Podcastaby zwrócić niestandardowy obiekt chroniący funkcje, na których klasa wewnętrznie polega, ale które należy ujawnić. Jest to wyjaśnione dalej w rozdziale 2 (Przedmioty) serii artykułów.

Możesz to powiedzieć ai bodziedziczyć po Podcast. Co teraz, jeśli chcesz dodać do Podcastu metodę, która będzie obowiązywała dla wszystkich po tym, jak została ai bzostała utworzona? W takim przypadku użyj .prototypenastępujących opcji:

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

Teraz zadzwoń ai bjeszcze raz:

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

Więcej informacji na temat prototypów można znaleźć tutaj . Jeśli chcesz zrobić więcej spadków, sugeruję przyjrzeć się temu .


W serii artykułów mam wymienione powyżej są bardzo zalecane , aby przeczytać, obejmują one również następujące tematy:

  1. Funkcje
  2. Obiekty
  3. Prototypy
  4. Wymuszanie nowości w funkcjach konstruktora
  5. Podnoszenie
  6. Automatyczne wstawianie średnika
  7. Właściwości statyczne i metody

Pamiętaj, że „funkcja” automatycznego wstawiania średnika w JavaScript (jak wspomniano w 6.) bardzo często powoduje dziwne problemy w kodzie. Dlatego wolę traktować to jako błąd niż funkcję.

Jeśli chcesz przeczytać więcej, oto dość interesujący artykuł MSDN na te tematy, niektóre z nich opisane zawierają jeszcze więcej szczegółów.

Co jest interesujące, aby przeczytać , jak również (także obejmujące zagadnienia wymienione powyżej) są te artykuły z MDN JavaScript Przewodnik :

Jeśli chcesz wiedzieć, jak emulować outparametry c # (np. In DateTime.TryParse(str, out result)) w JavaScript, możesz znaleźć przykładowy kod tutaj.


Ci z was, którzy pracują z IE (który nie ma konsoli JavaScript, chyba że otworzysz narzędzia programistyczne za pomocą F12i otworzysz kartę konsoli), mogą skorzystać z następującego fragmentu kodu . Pozwala na użycie console.log(msg);jak w powyższych przykładach. Wystarczy wstawić przed Podcastfunkcją.

Dla Twojej wygody oto powyższy kod w jednym pełnym pojedynczym fragmencie kodu:


Uwagi:

  • Kilka dobrych wskazówek, wskazówek i zaleceń dotyczących programowania JavaScript można znaleźć tutaj (najlepsze praktyki JavaScript) i tam („var” kontra „let”) . Zalecany jest również ten artykuł o niejawnych typecastach (przymus) .

  • Wygodnym sposobem używania klas i kompilowania ich w JavaScript jest TypeScript. Oto plac zabaw, na którym można znaleźć przykłady pokazujące, jak to działa. Nawet jeśli obecnie nie używasz TypeScript, możesz rzucić okiem, ponieważ możesz porównać TypeScript z wynikiem JavaScript w widoku obok siebie. Większość przykładów jest prosta, ale jest też przykład Raytracer, który możesz wypróbować natychmiast. Szczególnie polecam zapoznanie się z przykładami „Korzystanie z klas”, „Korzystanie z dziedziczenia” i „Korzystanie z ogólnych” poprzez wybranie ich w oknie combobox - są to ładne szablony, które można natychmiast wykorzystać w JavaScript. Maszynopis jest używany z Angular.

  • Aby uzyskać enkapsulację zmiennych lokalnych, funkcji itp. W JavaScript, sugeruję użycie wzoru podobnego do następującego (JQuery używa tej samej techniki):

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

Oczywiście możesz - i powinieneś - umieścić kod skryptu w osobnym *.jspliku; jest to po prostu napisane w wierszu, aby skrót był krótki.

Funkcje samo-wywołujące (znane również jako IIFE = wyrażenie funkcji natychmiastowego wywołania) opisano tutaj bardziej szczegółowo .


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

Zaktualizowana odpowiedź:

W ECMAScript 6 można tworzyć funkcje statyczne za pomocą staticsłowa kluczowego:

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

Klasy ES6 nie wprowadzają żadnej nowej semantyki dla statyki. W ES5 możesz zrobić to samo:

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

Możesz przypisać do właściwości, Fooponieważ w JavaScript funkcje są obiektami.


Foo.bar;zwraca funkcję przypisaną do niego, a nie ciąg zwracany przez funkcję, jak sugeruje komentarz.

Czy możesz dodać informacje o tym, jak ustawić (zastąpić) wartość statyczną w obu tych przykładach?
Wilt,

1
@ Wilt w obu przypadkach właściwość „static” jest po prostu właściwością funkcji, więc należy ją ustawić i zastąpić, tak jak każdą inną właściwość w JavaScript. W obu przypadkach można ustawić barwłaściwość Foodo 3tak:Foo.bar = 3;
Max Heiber


16

Poniższy przykład i wyjaśnienie pochodzą z książki Professional JavaScript for Web Developers 2nd Edition autorstwa Nicholasa Zakasa. Oto odpowiedź, której szukałem, więc pomyślałem, że warto ją tutaj dodać.

(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

PersonKonstruktor w tym przykładzie ma dostęp do prywatnej nazwy zmiennej, jak wykonać getName()i setName()metod. Korzystając z tego wzorca, zmienna nazwy staje się statyczna i będzie używana we wszystkich instancjach. Oznacza to, że wywołanie setName()jednej instancji wpływa na wszystkie inne instancje. Wywołanie setName()lub utworzenie nowej Personinstancji ustawia zmienną nazwy na nową wartość. Powoduje to, że wszystkie wystąpienia zwracają tę samą wartość.


wygląda konstruktor + prototyp (hybrydowy)
Ganesh Kumar

2
Spowoduje to umieszczenie obiektu Person w globalnej przestrzeni nazw. Nie jest to rozwiązanie, które poleciłbym.
Ghola

Nie sądzę, aby była to prawdziwa zmienna statyczna, ponieważ jest tworzona inaczej w każdym nowym obiekcie. Obiekt statyczny powinien być spójny we wszystkich obiektach dziedziczących po prototypie nadrzędnym?
lindsaymacvean,

1
@ Ghola Celem było wyjaśnienie, jak utworzyć zmienną statyczną. Właściwa przestrzeń nazw i unikanie globałów to osobny temat, który mógł zwiększyć złożoność odpowiedzi. To użytkownik decyduje, jak podłączyć konstruktor bez zanieczyszczania. Jeśli jest wystarczająco dobry dla Nicholasa Zakasa, jest dla mnie wystarczająco dobry.
Nate,

@lindsaymacvean Jest to zmienna statyczna, ponieważ pojedyncza wartość jest wspólna dla wszystkich instancji. Wartość może się zmienić. Jeśli jedna instancja zmieni wartość, wpłynie to na wszystkie instancje. Nie jest prawdopodobne, aby był użyty dokładnie tak samo jak w powyższym przykładzie. Zezwolenie na ustawienie wartości podczas tworzenia wystąpienia ma tylko pokazać, że jest to możliwe. Bardziej prawdopodobne jest użycie gettera i settera lub przynajmniej sprawdzenie, czy jest ustawiony na coś innego niż niezdefiniowany.
Nate,

15

Jeśli używasz nowej składni klasy , możesz teraz wykonać następujące czynności:

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

    console.log(MyClass.myStaticVariable);

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

To skutecznie tworzy zmienną statyczną w JavaScript.


Jest to przydatne podczas budowania statycznych klas narzędzi!
Indolering

1
Ale teraz pytanie brzmi: w jaki sposób utrwalasz wartość i zezwalasz na zmiany w seterze. Potrzebne byłoby zamknięcie lub właściwość MyClasszdefiniowana poza konstrukcją klasy.
trincot 16.04.18


8

Jeśli chcesz zadeklarować zmienne statyczne do tworzenia stałych w aplikacji, uznałem, że jest to najbardziej uproszczone podejście

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

Informacje o classwprowadzonym przez ECMAScript 2015. Pozostałe odpowiedzi nie są całkowicie jasne.

Oto przykład pokazujący, jak utworzyć statyczny var staticVarza pomocą ClassName. varskładnia:

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

Aby uzyskać dostęp do zmiennej statycznej, używamy .constructorwłaściwości, która zwraca odwołanie do funkcji konstruktora obiektów, która utworzyła klasę. Możemy to nazwać dwoma utworzonymi instancjami:

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

Istnieją inne podobne odpowiedzi, ale żadna z nich do mnie nie przemówiła. Oto, z czym skończyłem:

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

7

Oprócz reszty istnieje obecnie projekt (propozycja etapu 2 ) dotyczący propozycji ECMA, który wprowadza pola static publiczne na zajęciach. ( rozważono prywatne pola )

Na przykładzie z propozycji proponowana staticskładnia będzie wyglądać następująco:

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

i być równoważne z następującymi, które inni podkreślili:

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

Następnie możesz uzyskać do niego dostęp za pośrednictwem CustomDate.epoch.

Możesz śledzić nową propozycję w proposal-static-class-features.


Obecnie babel obsługuje tę funkcję za pomocą wtyczki właściwości klasy transform, której można użyć. Dodatkowo, choć wciąż jest w toku, V8wdraża go .


6

Możesz utworzyć zmienną statyczną w JavaScript tak jak poniżej. Oto countzmienna statyczna.

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

Możesz przypisać wartości do zmiennej statycznej za pomocą Personfunkcji lub dowolnego z instancji:

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

Jest to jedno z dobrych podejść do deklarowania zmiennej statycznej i uzyskiwania do niej dostępu w JavaScript.
ArunDhwaj IIITH

5

Jeśli chcesz utworzyć globalną zmienną statyczną:

var my_id = 123;

Zastąp zmienną poniższą:

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

4

Najbliższą rzeczą w JavaScript do zmiennej statycznej jest zmienna globalna - jest to po prostu zmienna zadeklarowana poza zakresem literału funkcji lub obiektu:

var thisIsGlobal = 1;

function foo() {
    var thisIsNot = 2;
}

Inną rzeczą, którą możesz zrobić, to przechowywać zmienne globalne w dosłownym obiekcie:

var foo = { bar : 1 }

A następnie uzyskać dostęp do variabels tak: foo.bar.


ten pomógł mi załadować wiele plików ..... var foo = {counter: 1}; function moreFiles () {fileName = "Plik" + foo.counter; foo.counter = foo.counter + 1;
veer7

4

Aby skondensować wszystkie koncepcje klas tutaj, przetestuj to:

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

Cóż, innym sposobem na przyjrzenie się najlepszym praktykom w tych sprawach jest po prostu zobaczenie, jak coffeescript tłumaczy te pojęcia.

#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

W JavaScript zmienne są domyślnie statyczne . Przykład :

var x = 0;

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

setInterval(draw, 1000);

Wartość x jest zwiększana o 1 co 1000 milisekund.
Będzie drukować 1,2,3 itd


2
To inna sprawa. Twój przykład dotyczy zakresów.
pretendent

4

Istnieje inne podejście, które rozwiązało moje wymagania po przejrzeniu tego wątku. Zależy to dokładnie od tego, co chcesz osiągnąć dzięki „zmiennej statycznej”.

Globalna właściwość sessionStorage lub localStorage pozwala na przechowywanie danych przez czas trwania sesji lub przez czas nieokreślony, aż do wyraźnego wyczyszczenia. Pozwala to na współdzielenie danych między wszystkimi oknami, ramkami, panelami kart, wyskakującymi oknami itp. Strony / aplikacji i jest znacznie potężniejszy niż zwykła „zmienna statyczna / globalna” w jednym segmencie kodu.

Pozwala to uniknąć wszelkich problemów związanych z zakresem, czasem życia, semantyką, dynamiką itp. Zmiennych globalnych najwyższego poziomu, tj. Window.myglobal. Nie wiem, jak wydajna jest, ale nie jest to ważne w przypadku niewielkich ilości danych, do których dostęp jest uzyskiwany przy niewielkich prędkościach.

Łatwo dostępne jako „sessionStorage.mydata = cokolwiek” i pobrane podobnie. Zobacz „JavaScript: The Definitive Guide, Sixth Edition”, David Flanagan, ISBN: 978-0-596-80552-4, rozdział 20, sekcja 20.1. Można go łatwo pobrać jako plik PDF za pomocą prostego wyszukiwania lub w subskrypcji O'Reilly Safaribooks (na wagę złota).


2

Funkcja / klasy zezwala tylko na jeden konstruktor dla swojego zakresu obiektowego. Function Hoisting, declarations & expressions

  • Funkcje utworzone za pomocą konstruktora funkcji nie tworzą zamknięć w swoich kontekstach tworzenia; zawsze są tworzone w zasięgu globalnym.

      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)

Zamknięcia - kopie zamknięcia są funkcją z zachowanymi danymi.

  • Kopie każdego zamknięcia są tworzone dla funkcji z własnymi wolnymi wartościami lub odniesieniami. Ilekroć używasz funkcji wewnątrz innej funkcji, używane jest zamknięcie.
  • Zamknięcie w JavaScript jest jak utrzymywanie kopii wszystkich lokalnych zmiennych jego funkcji nadrzędnej przez 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

Klasy funkcji ES5 : wykorzystuje Object.defineProperty (O, P, atrybuty)

Metoda Object.defineProperty () definiuje nową właściwość bezpośrednio na obiekcie lub modyfikuje istniejącą właściwość na obiekcie i zwraca obiekt.

Utworzono niektóre metody za pomocą `` , aby każdy raz mógł łatwo zrozumieć klasy funkcji.

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

Poniższy fragment kodu ma na celu sprawdzenie, czy każda instancja ma własną kopię elementów instancji i wspólnych elementów statycznych.

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

Wywołania metod statycznych są wykonywane bezpośrednio w klasie i nie można ich wywoływać w instancjach klasy. Ale można wywoływać wezwania do członków statycznych z wnętrza instancji.

Przy użyciu składni:

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

Klasy ES6: Klasy ES2015 są prostym cukrem w stosunku do prototypowego wzoru OO. Posiadanie pojedynczej wygodnej formy deklaratywnej ułatwia stosowanie wzorców klas i zachęca do interoperacyjności. Klasy obsługują dziedziczenie oparte na prototypach, super wywołania, metody instancji i statyczne oraz konstruktory.

Przykład : odnieś mój poprzedni post.


2

Istnieją 4 sposoby emulacji lokalnych zmiennych statycznych dla funkcji w JavaScript.

Metoda 1: Korzystanie z właściwości obiektu funkcji (obsługiwane w starych przeglądarkach)

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

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

Metoda 2: Korzystanie z zamknięcia, wariant 1 (obsługiwany w starych przeglądarkach)

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

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

Metoda 3: Użycie zamknięcia, wariant 2 (obsługiwany również w starszych przeglądarkach)

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

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

Metoda 4: Użycie zamknięcia, wariant 3 (wymaga obsługi EcmaScript 2015)

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

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

2

Możesz zdefiniować funkcje statyczne w JavaScript za pomocą staticsłowa kluczowego:

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

MyClass.myStaticFunction(); // 42

W chwili pisania tego tekstu nadal nie można zdefiniować właściwości statycznych (innych niż funkcje) w klasie. Właściwości statyczne są nadal propozycją etapu 3 , co oznacza, że ​​nie są jeszcze częścią JavaScript. Jednak nic nie stoi na przeszkodzie, abyś po prostu przypisał klasę, tak jak w przypadku każdego innego obiektu:

class MyClass {}

MyClass.myStaticProperty = 42;

MyClass.myStaticProperty; // 42

Uwaga końcowa: należy zachować ostrożność podczas używania obiektów statycznych z dziedziczeniem - wszystkie dziedziczone klasy współużytkują tę samą kopię obiektu .


1

W JavaScript nie ma statycznego terminu ani słowa kluczowego, ale możemy umieścić takie dane bezpośrednio w obiekcie funkcji (jak w każdym innym obiekcie).

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

Często używam zmiennych funkcji statycznych i szkoda, że ​​JS nie ma do tego wbudowanego mechanizmu. Zbyt często widzę kod, w którym zmienne i funkcje są zdefiniowane w zakresie zewnętrznym, nawet jeśli są one używane tylko w jednej funkcji. To brzydkie, podatne na błędy i po prostu prosi o kłopoty ...

Wymyśliłem następującą metodę:

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

Dodaje to metodę „statyki” do wszystkich funkcji (tak, rozluźnij się wokół niej), po wywołaniu doda pusty obiekt (_statics) do obiektu funkcji i zwróci go. Jeśli dostarczona jest funkcja init, statystyka zostanie ustawiona na wynik init ().

Następnie możesz wykonać:

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

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

Porównując to do IIFE, która jest drugą poprawną odpowiedzią, ma to tę wadę, że dodaje jedno przypisanie i jedno, jeśli przy każdym wywołaniu funkcji i dodaje do funkcji element „_statics”, jednak jest kilka zalet: argumenty są na góra nie w funkcji wewnętrznej, użycie „statycznego” w wewnętrznym kodzie funkcji jest jawne z „_s”. przedrostek i ogólnie łatwiej jest patrzeć i rozumieć.


1

Podsumowanie:

W ES6/ ES 2015 classsłowo kluczowe zostało wprowadzone wraz ze staticsłowem kluczowym towarzyszącym . Należy pamiętać, że jest to cukier składniowy w porównaniu z prototypowym modelem dziedziczenia, który ucieleśnia skrypt javavscript. Słowo statickluczowe działa w następujący sposób dla metod:

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
Prosił o zmienną statyczną, a nie funkcję statyczną.
Konrad Höffner

1

Użyłem prototypu i tak to działało:

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

Cat.COLLECTION_NAME = "cats";

lub za pomocą statycznego gettera:

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

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

0

Zmienne na poziomie okna są trochę podobne do statyki w tym sensie, że można użyć bezpośredniego odniesienia i są one dostępne dla wszystkich części aplikacji


3
O wiele lepszy opis takich zmiennych jest raczej „globalny” niż statyczny.
Patrick M,

0

W Javascript nie ma czegoś takiego jak zmienna statyczna. Ten język jest zorientowany obiektowo na prototypy, więc nie ma klas, ale prototypy, z których obiekty same się „kopiują”.

Możesz je symulować za pomocą zmiennych globalnych lub prototypowania (dodając właściwość do prototypu):

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

Ta metoda działa, ale zanieczyszczaszFunction.prototype
Dan

@Dan: Rozumiem, że byłoby to po prostu koło, a nie funkcja. Przynajmniej tak Chrome próbuje mi powiedzieć: function circle() {}| circle.prototype| circle.prototype.pi = 3.14| circle.prototype| Function.prototype| Function.__proto__(jeśli o to ci chodziło)
Aktau

0

Pracując ze stronami MVC korzystającymi z jQuery, chciałbym mieć pewność, że akcje AJAX w ramach niektórych programów obsługi zdarzeń będą mogły zostać wykonane dopiero po zakończeniu poprzedniego żądania. W tym celu używam „statycznej” zmiennej obiektowej jqXHR.

Biorąc pod uwagę następujący przycisk:

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

Zasadniczo używam takiego IIFE dla mojego modułu obsługi kliknięć:

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

Jeśli chcesz użyć prototypu, jest na to sposób

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

W ten sposób będziesz mógł uzyskać dostęp do zmiennej licznika z dowolnej instancji, a każda zmiana właściwości zostanie natychmiast odzwierciedlona !!

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.