Statičke varijable u javascriptu

Kako stvoriti statičke varijable u javascriptu?

553
08 окт. postavio Rajat 08. listopada 2009-10-08 07:31 '09 u 7:31 am 2009-10-08 07:31
@ 36 odgovora
  • 1
  • 2

Ako krenete od objektno orijentiranog jezika temeljenog na klasi (na primjer, Java, C ++ ili C #), pretpostavljam da pokušavate stvoriti varijablu ili metodu povezanu s "tipom", ali ne s instancom.

Primjer pomoću "klasičnog" pristupa, s funkcijama konstruktora, možda će vam pomoći razumjeti koncepte osnovnog OO JavaScripta:

 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 definiran u objektu staticProperty (što je funkcija) i nema nikakve veze sa svojim kreiranim instancama, JavaScript se odnosi na objekte prve klase , dakle, kao objekt, možete dodijeliti svojstva funkciji.

743
08 окт. odgovor daje CMS 08. listopada. 2009-10-08 07:49 '09 u 7:49 2009-10-08 07:49

Možete iskoristiti činjenicu da su JS funkcije i objekti, što znači da mogu imati svojstva.

Na primjer, navodeći primjer iz članka Statične varijable u Javascriptu, koji je sada nestao:

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

Ako ovu funkciju nazovete nekoliko puta, vidjet ćete prirast brojača.

border=0

A ovo je vjerojatno mnogo bolje rješenje od prebacivanja globalnog prostora imena s globalnom varijablom.


I tu je još jedno moguće rješenje temeljeno na zatvaranju: trik za korištenje statičkih varijabli u javascriptu :

 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. 

Koji vam daje isti rezultat - osim što se ovaj put vrijednost vraća s dodanom vrijednošću i ne prikazuje se.

465
08 окт. odgovor je dao Pascal MARTIN 8. listopada 2009-10-08 07:37 '09 u 7:37 AM 2009-10-08 07:37

To radite kroz IIFE (odmah nazvan izraz funkcija):

 var incr = (function () { var i = 1; return function () { return i++; } })(); incr(); // returns 1 incr(); // returns 2 
60
30 марта '13 в 13:02 2013-03-30 13:02 odgovor je dao khoomeister 30. ožujka '13 u 13:02 2013-03-30 13:02

Možete koristiti arguments.callee za pohranu "statičkih" varijabli (ovo je također korisno za anonimnu funkciju):

 function () { arguments.callee.myStaticVar = arguments.callee.myStaticVar || 1; arguments.callee.myStaticVar++; alert(arguments.callee.myStaticVar); } 
36
06 нояб. odgovor od gpilotino 06. studenog 2009-11-06 14:19 '09 u 14:19 2009-11-06 14:19
 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(); 
24
28 февр. odgovor dao jim_zike_huang 28. veljače. 2012-02-28 23:08 '12 u 23:08 2012-02-28 23:08

Vidio sam nekoliko sličnih odgovora, ali bih htio spomenuti da ovaj post opisuje ovo najbolje od svega, želio bih ga podijeliti s vama.

Evo koda preuzetog iz njega, koji sam modificirao da dobijem potpuni primjer, za koji se nadam da će koristiti zajednici, jer se može koristiti kao predložak dizajna za razrede.

On također odgovara na vaše pitanje:

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

U ovom primjeru možete pristupiti statičkim svojstvima / funkcijama na sljedeći način:

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

A svojstva / funkcije objekta su jednostavne:

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

Imajte na umu da u podcast.immutableProp () imamo zatvaranje: veza na _somePrivateVariable pohranjena je unutar funkcije.

Možete čak definirati gettere i seters . Pogledajte ovaj isječak koda (gdje je d prototip objekta za koji želite proglasiti svojstvo, y je privatna varijabla, koja nije vidljiva izvan konstruktora):

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

Definira svojstvo d.year kroz funkcije get i set - ako ne navedete set , onda je svojstvo samo za čitanje i ne može se promijeniti (zapamtite da nećete dobiti pogrešku ako je pokušate postaviti, ali nema učinka). Svako svojstvo ima mogućnost writable , configurable (dopusti promjenu nakon deklaracije) i enumerable (dopusti korištenje kao popisivač) atribute, koji su false po defaultu. Možete ih, na primjer, postaviti putem defineProperty u trećem parametru. enumerable: true .

Istina je i sintaksa:

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

koja definira svojstvo čitanja / pisanja a, samo za čitanje b svojstvo i c samo svojstvo pisanja, kroz koje možete pristupiti svojstvu.

primjena:

 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 

primjedbe:

Da biste izbjegli neočekivano ponašanje, ako zaboravite new ključnu riječ, predlažem da u funkciju Podcast dodate sljedeće:

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

Sada će oba sljedeća primjera funkcionirati prema očekivanjima:

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

Novi operator stvara novi objekt i kopira sva svojstva i metode, 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" 

Napominjemo također da u nekim situacijama može biti korisno koristiti return u funkciji konstruktora Podcasta za vraćanje prilagođenih objekata koji štite funkcije na koje se oslanjaju unutar sebe, ali koje treba utjecati. To je detaljnije objašnjeno u Poglavlju 2 (Objekti) serije članaka.

Možete reći da su a i b naslijeđeni od Podcast . Što ako želite dodati metodu u Podcast, koja se primjenjuje na sve njih nakon a i b , je instanced? U tom slučaju upotrijebite .prototype na sljedeći način:

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

Sada ponovno nazovite a i b :

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

Više o prototipovima pročitajte ovdje . Ako želite napraviti više nasljedstva, predlažem da proučite ovo .


Preporučuje se čitanje niza članaka koje sam spomenuo gore, a uključuju i sljedeće teme

  • funkcije
  • objekti
  • prototipova
  • Izvođenje novih konstruktorskih funkcija
  • dizanje
  • Automatska točka-zarez
  • Statička svojstva i metode

Imajte na umu da je automatska JavaScript "funkcija" zarezom (kao što je spomenuto u 6.) vrlo često odgovorna za izazivanje čudnih problema u vašem kodu. Stoga bih radije ovo tretirao kao pogrešku, a ne kao funkciju.

Ako želite saznati više, ovdje je prilično zanimljiv MSDN članak o ovim temama, od kojih su neke tamo opisane, te pružaju još detaljnije informacije.

Ono što je zanimljivo pročitati (uključujući i gore navedene teme) su oni članci iz vodiča za MDN JavaScript :


Oni koji rade s IE-om (koji nema konzolu za JavaScript, ako ne otvorite razvojne alate pomoću F12 i otvorite karticu konzole) mogu pronaći sljedeći isječak korisnim. To vam omogućuje da koristite console.log(msg); kako je korišteno u gornjim primjerima. Samo ga zalijepite ispred značajke Podcast .

Radi Vaše udobnosti, ovdje se nalazi gornji kôd u jednom cjelovitom isječku koda:


Napomena. , Praktičan način korištenja klasa i kompajliranja u JavaScriptu je TypeScript. Ovdje je platforma na kojoj možete pronaći nekoliko primjera kako to funkcionira. Čak i ako trenutno ne koristite TypeScript, možete pogledati, jer možete usporediti TypeScript s rezultatom javascripta rame uz rame. Većina primjera je jednostavna, ali postoji i primjer Raytracer, koji možete pokušati odmah. Preporučujem posebno proučavanje primjera "Korištenje klasa", "Korištenje nasljeđivanja" i "Korištenje zajedničkog" odabirom njih u comboboxu - to su prekrasni predlošci koje možete odmah koristiti u JavaScriptu.

21
10 сент. odgovor dao Matt Sep 10 2013-09-10 14:53 '13 u 14:53 2013-09-10 14:53

Ažurirani odgovor:

U ECMAScript 6 možete stvoriti statične funkcije pomoću static :

 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 

Razredi ES6 ne uvode nikakvu novu semantiku za statiku. Isto možete učiniti u ES5 na sljedeći način:

 //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žete dodijeliti svojstvo Foo jer postoje objekti u JavaScript funkcijama.

16
27 марта '15 в 4:09 2015-03-27 04:09 odgovor je dao Max Heiber 27. ožujka 2009. u 4:09 2015-03-27 04:09

Sljedeći primjer i objašnjenje nalaze se u knjizi Profesionalni JavaScript za web programere drugog izdanja Nicholasa Zakasa. Ovo je odgovor koji sam tražio, pa sam pomislio da bi bilo korisno dodati ga ovdje.

 (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 

U ovom primjeru konstruktor Person ima pristup imenu privatne varijable, kao i metodama setName() i setName() . Koristeći ovaj predložak, varijabla imena postaje statična i koristi se za sve instance. To znači da pozivanje setName() u jednom primjeru utječe na sve druge instance. Pozivanje setName() ili stvaranje nove instance Person postavlja varijablu imena za novu vrijednost. To uzrokuje da sve instance vraćaju istu vrijednost.

13
13 дек. Odgovor je dat Nate 13 Dec. 2011-12-13 11:26 '11 u 11:26 2011-12-13 11:26

Ako koristite novu sintaksu klase , možete učiniti sljedeće:

5
22 февр. odgovor je automatski . 22. veljače. 2017-02-22 19:11 '17 u 19:11 2017-02-22 19:11

Ako želite prijaviti statičke varijable za stvaranje konstanti u vašoj aplikaciji, pronašao sam sljedeće kao najjednostavniji pristup

 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; 
4
03 апр. Odgovor dao je Hemant 03. travnja 2013-04-03 01:05 '13 u 1:05 2013-04-03 01:05

Postoje i drugi slični odgovori, ali nitko od njih mi se nije obratio. Evo što sam završio:

 var nextCounter = (function () { var counter = 0; return function() { var temp = counter; counter += 1; return temp; }; })(); 
4
08 февр. odgovor je dat na funroll 08 fevr . 2015-02-08 06:34 '15 u 6:34 am 2015-02-08 06:34

Možete stvoriti statičnu varijablu u javascriptu kao što je prikazano u nastavku. Ovdje je count statička varijabla.

 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žete dodijeliti vrijednosti statičkoj varijabli pomoću funkcije Person ili bilo koje od instanci:

 // 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 
3
31 июля '16 в 9:16 2016-07-31 09:16 odgovor je dobio Snađoshƒaӽ 31. srpnja '16 u 9:16 2016-07-31 09:16

Ako želite stvoriti globalnu statičku varijablu:

 var my_id = 123; 

Zamijenite varijablu na sljedeći način:

 Object.defineProperty(window, 'my_id', { get: function() { return 123; }, configurable : false, enumerable : false }); 
3
16 марта '12 в 6:56 2012-03-16 06:56 odgovor je dao JoolzCheat 16. ožujka 2012. u 6:56 2012-03-16 06:56

O class predstavio ECMAScript 2015. Ostali odgovori nisu posve jasni.

Evo primjera koji pokazuje kako stvoriti statičku var staticVar pomoću ClassName . var synthax:

 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 

Za pristup statičkoj varijabli koristimo svojstvo .constructor , koje vraća referencu na konstruktor objekta koji je stvorio klasu. Možemo ga nazvati u dvije kreirane instance:

 MyClass.staticVar = 11; console.log(class1.constructor.staticVar); // 11 console.log(class2.constructor.staticVar); // 11 <-- yes it static! :) MyClass.staticVar = 12; console.log(class1.constructor.staticVar); // 12 console.log(class2.constructor.staticVar); // 12 
3
24 марта '17 в 13:02 2017-03-24 13:02 odgovor je dao COil 24. ožujka 2006. u 13:02 2017-03-24 13:02

Najbliža stvar u JavaScriptu za statičku varijablu je globalna varijabla - to je samo varijabla koja je objavljena izvan opsega funkcije ili literalnog objekta:

 var thisIsGlobal = 1; function foo() { var thisIsNot = 2; } 

Još jedna stvar koju možete učiniti je pohraniti globalne varijable unutar objektnog literala na sljedeći način:

 var foo = { bar : 1 } 

Zatim pristupite varijablama poput ovog: foo.bar .

2
08 окт. odgovor Andrew Hare listopad 08 2009-10-08 07:33 '09 u 7:33 am 2009-10-08 07:33

Zadane JavaScript varijable su statične . primjer:

 var x = 0; funkcija draw () { upozorenje (x);  // x + = 1; } setInterval (nacrtati, 1000);

Vrijednost x se povećava za 1 na svakih 1000 milisekundi.
Ispisat će 1,2,3 i više.

2
08 апр. Odgovor daje Kerim 08. travnja 2017-04-08 15:39 '17 u 15:39 2017-04-08 15:39

Za sažimanje svih koncepata razreda, provjerite ovo:

 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 

Pa, još jedan način da se pogleda najbolja praksa u tim stvarima je samo vidjeti kako coffeescript prevodi te koncepte.

 #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); 
2
24 нояб. odgovor daje Stratboy 24. studenog. 2013-11-24 14:20 '13 u 14:20 sati 2013-11-24 14:20

Postojao je drugačiji pristup koji je odlučivao o mojim zahtjevima nakon pregledavanja ove teme. To ovisi o tome što želite postići s "statičkom varijablom".

Svojstvo globalnog sessionStoragea ili localStorage omogućuje pohranjivanje podataka tijekom sesije ili na neodređeno duže razdoblje, sve dok nije eksplicitno izbrisano. To omogućuje dijeljenje podataka između svih prozora, okvira, kartica, skočnih prozora itd. Vaše stranice / aplikacije i mnogo moćniji od jednostavne "statičke / globalne varijable" u jednom segmentu koda.

On izbjegava sve probleme s opsegom, životnim vijekom, semantikom, dinamikom itd. globalne varijable gornje razine, tj. Window.myglobal. Ne znam koliko je to učinkovito, ali nije važno za skromne količine podataka, pristup kojima se ostvaruje u skromnim količinama.

Jednostavan za pristup kao "sessionStorage.mydata = ništa" i na isti način. Vidi "JavaScript: Završni vodič, šesto izdanje", David Flanagan, ISBN: 978-0-596-80552-4, poglavlje 20, odjeljak 20.1. Lako je preuzeti u PDF formatu jednostavnim pretraživanjem ili pretplatom na O'Reilly Safaribooks (vrijedno zlata).

Pozdrav, Greg E

2
07 апр. Odgovori Greg E 07 Apr 2013-04-07 12:58 '13 u 12:58 2013-04-07 12:58

Ako želite koristiti prototip, postoji način

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

Na taj način možete pristupiti varijabli brojača iz bilo koje instance, a svaka promjena u imovini će se odmah odraziti!

0
09 мая '14 в 9:25 2014-05-09 09:25 odgovor je dao charlie Svibanj 09 '14 u 9:25 2014-05-09 09:25

U JavaScriptu nema statičnog pojma ili ključne riječi, ali takve podatke možemo staviti izravno u objekt funkcije (kao u bilo kojem drugom objektu).

 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 
0
31 марта '16 в 20:44 2016-03-31 20:44 odgovor je dao Satyapriya Mishra 31. ožujka 2011. u 20:44 2016-03-31 20:44

Za privatne statičke varijable pronašao sam ovu metodu:

 function Class() { } Class.prototype = new function() { _privateStatic = 1; this.get = function() { return _privateStatic; } this.inc = function() { _privateStatic++; } }; var o1 = new Class(); var o2 = new Class(); o1.inc(); console.log(o1.get()); console.log(o2.get()); // 2 
0
25 окт. Odgovor dao Martin Wantke 25. listopada 2016-10-25 15:42 '16 u 15:42 2016-10-25 15:42

Dakle, ono što vidim s drugim odgovorima je da oni ne uzimaju u obzir temeljni arhitektonski zahtjev statičkog atributa u objektno orijentiranom programiranju.