Variabel statis dalam JavaScript

716

Bagaimana saya bisa membuat variabel statis di Javascript?

Rajat
sumber
kita dapat mendefinisikan label atau tag html lainnya dengan atribut gaya "dispaly: none" dan mengatur nilai variabel untuk nilai ini dan operasi pada nilai ini. Jangan susah-susah.
asghar
Solusi paling sederhana yang saya temukan: jangan mendefinisikan variabel statis di kelas sama sekali. Ketika Anda ingin menggunakan variabel statis, cukup tentukan di sana dan kemudian, mis someFunc = () => { MyClass.myStaticVariable = 1; }. Kemudian cukup buat metode statis untuk mengembalikan anggota statis, mis static getStatic() { return MyClass.myStaticVariable; }. Maka Anda bisa menelepon MyClass.getStatic()dari luar kelas untuk mendapatkan data statis!
Pixel

Jawaban:

863

Jika Anda berasal dari bahasa berorientasi objek berbasis kelas, diketik secara statis (seperti Java, C ++ atau C #) Saya berasumsi bahwa Anda mencoba untuk membuat variabel atau metode yang terkait dengan "tipe" tetapi tidak ke sebuah instance.

Contoh menggunakan pendekatan "klasik", dengan fungsi konstruktor mungkin dapat membantu Anda menangkap konsep JavaScript OO dasar:

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

staticPropertydidefinisikan dalam objek MyClass (yang merupakan fungsi) dan tidak ada hubungannya dengan instance yang dibuat, JavaScript memperlakukan fungsi sebagai objek kelas satu , jadi sebagai objek, Anda dapat menetapkan properti ke fungsi.

UPDATE: ES6 memperkenalkan kemampuan untuk mendeklarasikan kelas melalui classkata kunci. Ini adalah gula sintaks atas warisan berbasis prototipe yang ada.

Kata statickunci memungkinkan Anda untuk dengan mudah mendefinisikan properti atau metode statis di kelas.

Mari kita lihat contoh di atas diimplementasikan dengan kelas ES6:

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

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

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

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

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

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

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

CMS
sumber
5
Agaknya privilegedMethodtidak setara dengan metode pribadi di OO karena sepertinya itu bisa dipanggil pada instance dari MyClass? Apakah maksud Anda ini istimewa karena dapat mengakses privateVariable?
Donal
3
Tidak this.constructordapat digunakan untuk mengakses variabel statis dari "metode instance"? Jika ya, ada baiknya menambahkannya ke jawaban.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
1
Anda juga bisa menyebutkan fungsi statis dalam contoh Anda.
David Rodrigues
18
hai, saya tidak yakin saya setuju dengan baris ini // Variabel statis yang dibagikan oleh semua instance 'MyClass.staticProperty = "baz";' bagi saya yang menyimpulkan bahwa Anda dapat menemukan baz dari 'myInstance.staticProperty' yang tentu saja Anda tidak bisa.
fullstacklife
5
Mungkin itu harus membaca MyClass.prototype.staticProperty = "baz";atau bahkan lebih benar dengan prinsip-prinsip OO properti statis sebenarnya harus didefinisikan sebagai fungsi anonim MyClass.prototype.staticProperty = function () {return staticVar;}dan sehingga semua instance mengakses variabel tunggal yang juga dapat diubah dengan setter.
lindsaymacvean
535

Anda mungkin mengambil keuntungan dari fakta bahwa fungsi JS juga objek - yang berarti mereka dapat memiliki properti.

Misalnya, dengan mengutip contoh yang diberikan pada variabel Statis artikel (sekarang lenyap) dalam 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);
}

Jika Anda memanggil fungsi itu beberapa kali, Anda akan melihat penghitung bertambah.

Dan ini mungkin solusi yang jauh lebih baik daripada mencemari namespace global dengan variabel global.


Dan berikut ini adalah solusi yang mungkin, berdasarkan penutupan: Trik menggunakan variabel statis dalam 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.

Yang memberi Anda hasil yang sama - kecuali, kali ini, nilai yang bertambah dikembalikan, alih-alih ditampilkan.

Pascal MARTIN
sumber
50
sebagai jalan pintas, Anda bisa melakukannya countMyself.counter = countMyself.counter || initial_value;jika variabel statis tidak akan pernah menjadi falsey (false, 0, null, atau string kosong)
Kip
3
Sedikit lebih pendek dan lebih jelas: (function () {var id = 0; function uniqueID () {return id ++;};}) ();
Tom Robinson
3
Counter in closure sangat cepat daripada di kelasnya di Firefox. jsperf.com/static-counter-in-class-vs-in-closure
Sony Santos
Gunakan ===untuk typeofcek lain, Anda akan mendapatkan paksaan aneh.
dewd
@SonySantos Tes Anda menunjukkan yang sebaliknya untuk Firefox 40
bartolo-otrit
96

Anda melakukannya melalui IIFE (ekspresi fungsi yang langsung dipanggil):

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

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

incr(); // returns 1
incr(); // returns 2
khoomeister
sumber
21
Saya akan mengatakan ini adalah cara paling idiomatis untuk melakukannya dalam JavaScript. Sayang sekali tidak mendapatkan upvotes terlalu banyak berkat metode lain yang mungkin lebih cocok untuk orang-orang yang berasal dari bahasa lain.
1
Saya ulangi menggunakan 'penutupan' bukan hanya 'IIFE'.
zendka
39

Anda dapat menggunakan arguments.callee untuk menyimpan variabel "statis" (ini juga berguna dalam fungsi anonim):

function () {
  arguments.callee.myStaticVar = arguments.callee.myStaticVar || 1;
  arguments.callee.myStaticVar++;
  alert(arguments.callee.myStaticVar);
}
gpilotino
sumber
3
Sejauh yang saya mengerti, metode ini memiliki satu (hanya satu?) Keunggulan dibandingkan cara pascal MARTIN: Anda dapat menggunakannya pada fungsi anonim. Contoh dari ini akan menjadi luar biasa
Dan
27
arguments.calleesudah ditinggalkan.
Quolonel Questions
Saya cukup banyak mencemooh JS sepanjang waktu, tetapi calleesepertinya hal yang baik untuk dimiliki. Saya bertanya-tanya mengapa peretasan membuat mereka memutuskan untuk mencabut ini ...: |
user2173353
35

Saya telah melihat beberapa jawaban yang serupa, tetapi saya ingin menyebutkan bahwa posting ini paling menggambarkannya, jadi saya ingin membagikannya dengan Anda.

Inilah beberapa kode yang diambil darinya, yang telah saya modifikasi untuk mendapatkan contoh lengkap yang semoga bermanfaat bagi komunitas karena dapat digunakan sebagai templat desain untuk kelas.

Itu juga menjawab pertanyaan Anda:

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

Dengan contoh itu, Anda dapat mengakses properti / fungsi statis sebagai berikut:

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

Dan objek properti / fungsi cukup sebagai:

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

Perhatikan bahwa di podcast.immutableProp (), kami memiliki penutup : Referensi ke _somePrivateVariable disimpan di dalam fungsi.

Anda bahkan dapat mendefinisikan getter dan setter . Lihatlah potongan kode ini (di mana dprototipe objek yang ingin Anda deklarasikan properti, yadalah variabel pribadi yang tidak terlihat di luar konstruktor):

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

Ini mendefinisikan properti d.yearvia getdan setfungsinya - jika Anda tidak menentukan set, maka properti tersebut hanya baca dan tidak dapat dimodifikasi (perlu diketahui bahwa Anda tidak akan mendapatkan kesalahan jika Anda mencoba mengaturnya, tetapi tidak berpengaruh). Setiap properti memiliki atribut writable, configurable(diizinkan untuk mengubah setelah deklarasi) dan enumerable(memungkinkan untuk menggunakannya sebagai enumerator), yang sesuai standar false. Anda dapat mengaturnya melalui definePropertyparameter ke-3, mis enumerable: true.

Yang juga valid adalah sintaks ini:

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

yang mendefinisikan properti yang dapat dibaca / ditulis a, properti hanya-baca bdan properti hanya-tulis c, di mana properti adapat diakses.

Pemakaian:

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

Catatan:

Untuk menghindari perilaku tak terduga jika Anda lupa newkata kunci, saya sarankan Anda menambahkan fungsi berikut Podcast:

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

Sekarang kedua instantiasi berikut akan berfungsi seperti yang diharapkan:

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

Pernyataan 'baru' membuat objek baru dan menyalin semua properti dan metode, yaitu

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"

Perhatikan juga, bahwa dalam beberapa situasi akan berguna untuk menggunakan returnpernyataan dalam fungsi konstruktor Podcastuntuk mengembalikan fungsi kustom objek yang dilindungi kelas secara internal tetapi bergantung pada yang perlu diekspos. Ini dijelaskan lebih lanjut dalam bab 2 (Objek) dari seri artikel.

Anda bisa mengatakan itu adan bmewarisi dari Podcast. Sekarang, bagaimana jika Anda ingin menambahkan metode ke Podcast yang berlaku untuk semuanya setelah adan btelah di-instanciated? Dalam hal ini, gunakan yang .prototypeberikut ini:

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

Sekarang telepon adan blagi:

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

Anda dapat menemukan detail lebih lanjut tentang prototipe di sini . Jika Anda ingin melakukan lebih banyak warisan, saya sarankan melihat ke dalam ini .


Seri artikel yang saya sebutkan di atas sangat disarankan untuk dibaca, termasuk juga topik-topik berikut:

  1. Fungsi
  2. Benda
  3. Prototipe
  4. Menerapkan Fungsi Baru pada Konstruktor
  5. Mengangkat
  6. Penyisipan titik koma otomatis
  7. Properti dan Metode Statis

Perhatikan bahwa penyisipan titik koma otomatis "fitur" dari JavaScript (sebagaimana disebutkan dalam 6.) seringkali bertanggung jawab untuk menyebabkan masalah aneh pada kode Anda. Oleh karena itu, saya lebih suka menganggapnya sebagai bug daripada sebagai fitur.

Jika Anda ingin membaca lebih lanjut, berikut ini adalah artikel MSDN yang cukup menarik tentang topik-topik ini, beberapa di antaranya dijelaskan di sana memberikan lebih banyak detail.

Yang juga menarik untuk dibaca (juga mencakup topik-topik yang disebutkan di atas) adalah artikel-artikel dari MDN JavaScript Guide :

Jika Anda ingin tahu cara meniru outparameter c # (seperti dalam DateTime.TryParse(str, out result)) dalam JavaScript, Anda dapat menemukan kode sampel di sini.


Anda yang bekerja dengan IE (yang tidak memiliki konsol untuk JavaScript kecuali Anda membuka alat pengembang menggunakan F12dan membuka tab konsol) mungkin menemukan potongan berikut ini bermanfaat. Ini memungkinkan Anda untuk menggunakan console.log(msg);sebagaimana digunakan dalam contoh di atas. Cukup masukkan sebelum Podcastfungsi.

Untuk kenyamanan Anda, inilah kode di atas dalam satu cuplikan kode tunggal lengkap:


Catatan:

  • Beberapa tips, petunjuk, dan rekomendasi yang bagus tentang pemrograman JavaScript secara umum dapat Anda temukan di sini (praktik terbaik JavaScript) dan di sana ('var' versus 'let') . Juga disarankan artikel ini tentang typecasts implisit (pemaksaan) .

  • Cara mudah untuk menggunakan kelas dan mengompilasinya ke dalam JavaScript adalah TypeScript. Berikut adalah taman bermain di mana Anda dapat menemukan beberapa contoh yang menunjukkan kepada Anda cara kerjanya. Bahkan jika Anda tidak menggunakan TypeScript saat ini, Anda dapat melihatnya karena Anda dapat membandingkan TypeScript dengan hasil JavaScript pada tampilan berdampingan. Sebagian besar contoh sederhana, tetapi ada juga contoh Raytracer yang dapat Anda coba secara instan. Saya sarankan terutama melihat contoh "Menggunakan Kelas", "Menggunakan Warisan" dan "Menggunakan Generik" dengan memilihnya di kotak kombo - ini adalah templat yang bagus yang dapat langsung Anda gunakan dalam JavaScript. Naskah digunakan dengan Angular.

  • Untuk mencapai enkapsulasi variabel lokal, fungsi dll dalam JavaScript, saya sarankan untuk menggunakan pola seperti berikut (JQuery menggunakan teknik yang sama):

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

Tentu saja, Anda dapat - dan harus - memasukkan kode skrip ke dalam *.jsfile terpisah ; ini hanya ditulis sebaris untuk menjaga contoh singkat.

Fungsi self-invocing (juga dikenal sebagai IIFE = Ekspresi Fungsi Segera Diminta) dijelaskan lebih rinci di sini .

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

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

Jawaban yang diperbarui:

Di ECMAScript 6 , Anda dapat membuat fungsi statis menggunakan statickata kunci:

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

Kelas ES6 tidak memperkenalkan semantik baru untuk statika. Anda dapat melakukan hal yang sama di ES5 seperti ini:

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

Anda dapat menetapkan ke properti Fookarena dalam fungsi JavaScript adalah objek.

Max Heiber
sumber
Foo.bar;mengembalikan fungsi yang ditugaskan padanya, bukan string yang dikembalikan oleh fungsi seperti komentar Anda.
Bisakah Anda menambahkan beberapa informasi tentang cara menetapkan (menimpa) nilai statis dalam kedua contoh tersebut?
Layu
1
@Wilt dalam kedua kasus, properti "statis" hanyalah properti pada fungsi, jadi Anda mengaturnya dan menimpanya seperti Anda akan properti lain di JavaScript. Dalam kedua kasus, Anda dapat mengatur barproperti Foomenjadi 3seperti ini:Foo.bar = 3;
Max Heiber
ES6 pertanyaan spesifik: stackoverflow.com/questions/28445693/…
Ciro Santilli 郝海东 冠状 病 六四 六四 事件 法轮功
16

Contoh dan penjelasan berikut berasal dari buku Professional JavaScript for Web Developers 2nd Edition karya Nicholas Zakas. Ini adalah jawaban yang saya cari jadi saya pikir akan sangat membantu untuk menambahkannya di sini.

(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

The Personkonstruktor dalam contoh ini memiliki akses ke nama variabel pribadi, seperti melakukan getName()dan setName()metode. Dengan menggunakan pola ini, variabel nama menjadi statis dan akan digunakan di antara semua instance. Ini berarti memanggil setName()satu instance mempengaruhi semua instance lainnya. Memanggil setName()atau membuat Personinstance baru akan menetapkan variabel nama ke nilai baru. Ini menyebabkan semua instance mengembalikan nilai yang sama.

Nate
sumber
terlihat konstruktor + prototipe (hybrid)
Ganesh Kumar
2
Ini menempatkan objek Person di namespace global. Bukan solusi yang saya sarankan.
Ghola
Saya tidak berpikir ini adalah variabel statis sejati karena ini dipakai secara berbeda dengan setiap objek baru. Objek statis harus konsisten di semua objek yang diwarisi dari prototipe induk?
lindsaymacvean
1
@Ghola Maksud di sini adalah untuk menjelaskan cara membuat variabel statis. Penempatan nama yang tepat dan menghindari global adalah topik terpisah yang mungkin menambah kompleksitas jawabannya. Terserah kepada pengguna untuk menentukan cara memasang konstruktor tanpa mencemari. Jika itu cukup baik untuk Nicholas Zakas, itu cukup baik untukku.
Nate
@lindsaymacvean Ini adalah variabel statis karena nilai tunggal dibagikan di semua contoh. Tidak apa-apa jika nilainya berubah. Jika satu instance mengubah nilai, semua instance akan terpengaruh. Sepertinya tidak akan digunakan persis sama dengan contoh di atas. Mengizinkan nilai yang akan ditetapkan selama instantiasi hanya untuk menunjukkan bahwa itu mungkin. Kasus penggunaan yang lebih mungkin adalah hanya memiliki pengambil dan penyetel atau setidaknya memeriksa untuk memastikan itu diatur ke sesuatu selain yang tidak ditentukan.
Nate
15

Jika Anda menggunakan sintaks kelas baru maka Anda sekarang dapat melakukan hal berikut:

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

    console.log(MyClass.myStaticVariable);

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

Ini secara efektif membuat variabel statis dalam JavaScript.

Otomatis
sumber
Ini berguna ketika membangun kelas utilitas statis!
Indolering
1
Tetapi sekarang pertanyaannya adalah bagaimana Anda bertahan suatu nilai dan mengizinkan perubahan itu dengan setter. Penutupan akan dibutuhkan atau properti pada MyClassdefinisi di luar konstruksi kelas.
trincot
Terkait: stackoverflow.com/questions/28445693/…
Ciro Santilli 郝海东 冠状 病 六四 六四 事件 法轮功
8

Jika Anda ingin mendeklarasikan variabel statis untuk membuat konstanta dalam aplikasi Anda maka saya menemukan berikut ini sebagai pendekatan yang paling sederhana

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

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

Tentang class diperkenalkan oleh ECMAScript 2015. Jawaban lainnya tidak sepenuhnya jelas.

Berikut adalah contoh yang menunjukkan cara membuat var statis staticVardengan ClassName. varsintaks:

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

Untuk mengakses variabel statis, kami menggunakan .constructorproperti yang mengembalikan referensi ke fungsi konstruktor objek yang membuat kelas. Kita dapat menyebutnya di dua instance yang dibuat:

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

Ada jawaban serupa lainnya, tetapi tidak ada yang cukup menarik bagi saya. Inilah yang akhirnya saya dapatkan:

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

Selain yang lain, saat ini ada rancangan ( proposal tahap-2 ) tentang Proposal ECMA yang memperkenalkan bidang static publik di kelas. ( bidang pribadi dipertimbangkan )

Menggunakan contoh dari proposal, staticsintaks yang diusulkan akan terlihat seperti ini:

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

dan setara dengan yang berikut yang telah disorot orang lain:

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

Anda kemudian dapat mengaksesnya melalui CustomDate.epoch.

Anda dapat melacak proposal baru di proposal-static-class-features.


Saat ini, babel mendukung fitur ini dengan plugin transformasi properti kelas yang dapat Anda gunakan. Selain itu, meskipun masih dalam proses, V8sedang mengimplementasikannya .

Dimitris Fasarakis Hilliard
sumber
6

Anda dapat membuat variabel statis dalam JavaScript seperti di bawah ini. Ini countadalah variabel statis.

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

Anda dapat menetapkan nilai ke variabel statis menggunakan Personfungsi, atau salah satu dari instance:

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

// set static variable using Person
Person.count = 20;
console.log(p1.constructor.count); // prints 20
Sнаđошƒаӽ
sumber
Ini adalah salah satu pendekatan yang baik untuk mendeklarasikan variabel statis dan mengaksesnya dalam JavaScript.
ArunDhwaj IIITH
5

Jika Anda ingin membuat variabel statis global:

var my_id = 123;

Ganti variabel dengan yang di bawah ini:

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

Hal terdekat dalam JavaScript ke variabel statis adalah variabel global - ini hanyalah variabel yang dideklarasikan di luar lingkup fungsi atau objek literal:

var thisIsGlobal = 1;

function foo() {
    var thisIsNot = 2;
}

Hal lain yang bisa Anda lakukan adalah menyimpan variabel global di dalam objek literal seperti ini:

var foo = { bar : 1 }

Dan kemudian mengakses Variabel seperti ini: foo.bar.

Andrew Hare
sumber
yang ini membantu saya mengunggah banyak file ..... var foo = {counter: 1}; function moreFiles () {fileName = "File" + foo.counter; foo.counter = foo.counter + 1;
veer7
4

Untuk menyingkat semua konsep kelas di sini, uji ini:

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

Nah, cara lain untuk melihat praktik terbaik dalam hal ini, adalah dengan melihat bagaimana coffeescript menerjemahkan konsep-konsep ini.

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

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

 t = new Test('inst_prop');

 console.log(Test.prop);


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

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

    return Test;

  })();

  t = new Test('inst_prop');

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

Dalam JavaScript variabel statis secara default. Contoh :

var x = 0;

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

setInterval(draw, 1000);

Nilai x bertambah 1 setiap 1000 milidetik.
Ini akan mencetak 1,2,3 dan seterusnya

Kerim
sumber
2
Itu kasus yang berbeda. Contoh Anda adalah tentang cakupan.
challet
4

Ada pendekatan lain, yang memecahkan persyaratan saya setelah menelusuri utas ini. Tergantung pada apa yang ingin Anda capai dengan "variabel statis".

Sesi properti global, Storage atau localStorage, memungkinkan data disimpan selama umur sesi, atau untuk periode yang lebih lama tanpa batas hingga masing-masing dihapus secara eksplisit. Ini memungkinkan data untuk dibagikan di antara semua jendela, bingkai, panel tab, popup, dll dari halaman / aplikasi Anda dan jauh lebih kuat daripada "variabel statis / global" sederhana dalam satu segmen kode.

Itu menghindari semua kerumitan dengan ruang lingkup, seumur hidup, semantik, dinamika dll dari variabel global tingkat atas, yaitu Window.myglobal. Tidak tahu seberapa efisien itu, tetapi itu tidak penting untuk jumlah data yang sederhana, diakses dengan kecepatan sedang.

Mudah diakses sebagai "sessionStorage.mydata = apa pun" dan diambil dengan cara yang sama. Lihat "JavaScript: Panduan Definitif, Edisi Keenam", David Flanagan, ISBN: 978-0-596-80552-4, Bab 20, bagian 20.1. Ini mudah diunduh sebagai PDF dengan pencarian sederhana, atau dalam langganan O'Reilly Safaribooks Anda (senilai dengan emas).

Greg E
sumber
2

Fungsi / kelas hanya memungkinkan konstruktor tunggal untuk cakupan objeknya. Function Hoisting, declarations & expressions

  • Fungsi yang dibuat dengan konstruktor fungsi tidak membuat penutupan untuk konteks penciptaannya; mereka selalu diciptakan dalam lingkup global.

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

Penutupan - salinan penutupan berfungsi dengan data yang disimpan.

  • Setiap salinan penutupan dibuat untuk suatu fungsi dengan nilai atau referensi gratisnya sendiri, Setiap kali Anda menggunakan fungsi di dalam fungsi lain, penutupan digunakan.
  • Penutupan dalam JavaScript adalah seperti mempertahankan salinan semua variabel lokal dari fungsi induknya oleh fungsi dalam.

      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

Kelas Fungsi ES5 : using Object.defineProperty (O, P, Attributes)

Metode Object.defineProperty () mendefinisikan properti baru secara langsung pada objek, atau memodifikasi properti yang ada pada objek, dan mengembalikan objek.

Dibuat beberapa metode dengan menggunakan `` , Sehingga setiap kali dapat memahami fungsi kelas dengan mudah.

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

Cuplikan kode di bawah ini untuk menguji tentang Setiap instance memiliki salinannya sendiri anggota instance dan anggota statis umum.

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

Metode statisPanggilan dilakukan langsung di kelas dan tidak dapat dipanggil pada instance kelas. Tetapi Anda dapat mencapai panggilan untuk anggota statis dari dalam instance.

Menggunakan sintaks:

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

Kelas ES6: Kelas ES2015 adalah gula sederhana di atas pola OO berbasis prototipe. Memiliki satu bentuk deklaratif yang nyaman membuat pola kelas lebih mudah digunakan, dan mendorong interoperabilitas. Kelas mendukung warisan berbasis prototipe, panggilan super, contoh dan metode statis dan konstruktor.

Contoh : lihat posting saya sebelumnya.

Yash
sumber
2

Ada 4 cara untuk meniru fungsi-variabel statis lokal di Javascript.

Metode 1: Menggunakan properti objek fungsi (didukung di browser lama)

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

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

Metode 2: Menggunakan penutupan, varian 1 (didukung di browser lama)

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

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

Metode 3: Menggunakan penutupan, varian 2 (juga didukung di browser lama)

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

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

Metode 4: Menggunakan penutupan, varian 3 (membutuhkan dukungan untuk EcmaScript 2015)

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

someFunc4() ; //prints 1
someFunc4() ; //prints 2
someFunc4() ; //prints 3
Mendapatkan gratis
sumber
2

Anda dapat menentukan fungsi statis dalam JavaScript menggunakan statickata kunci:

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

MyClass.myStaticFunction(); // 42

Pada tulisan ini, Anda masih tidak dapat mendefinisikan properti statis (selain fungsi) di dalam kelas. Properti statis masih merupakan proposal Tahap 3 , yang berarti mereka belum menjadi bagian dari JavaScript. Namun, tidak ada yang menghentikan Anda dari hanya menetapkan ke kelas seperti yang Anda lakukan pada objek lain:

class MyClass {}

MyClass.myStaticProperty = 42;

MyClass.myStaticProperty; // 42

Catatan akhir: berhati-hatilah dalam menggunakan objek statis dengan pewarisan - semua kelas yang diwarisi berbagi salinan objek yang sama .

vkarpov15
sumber
1

Dalam JavaScript, tidak ada istilah atau kata kunci statis, tetapi kita dapat menempatkan data tersebut langsung ke objek fungsi (seperti di objek lain).

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

f(); // Call No 1

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

Saya sering menggunakan variabel fungsi statis dan ini memalukan. JS tidak memiliki mekanisme bawaan untuk itu. Terlalu sering saya melihat kode di mana variabel dan fungsi didefinisikan dalam lingkup luar meskipun mereka hanya digunakan di dalam satu fungsi. Ini jelek, rawan kesalahan dan hanya meminta masalah ...

Saya datang dengan metode berikut:

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

Ini menambahkan metode 'statika' ke semua fungsi (ya, cukup santai saja), ketika dipanggil akan menambah objek kosong (_statika) ke objek fungsi dan mengembalikannya. Jika fungsi init disediakan _statics akan diatur ke init () hasilnya.

Anda kemudian dapat melakukan:

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

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

Membandingkan ini dengan IIFE yang merupakan jawaban yang benar lainnya, ini memiliki kekurangan menambahkan satu tugas dan satu jika pada setiap panggilan fungsi dan menambahkan anggota '_statics' ke fungsi, namun ada beberapa keuntungan: argumen ada di bagian atas tidak dalam fungsi internal, menggunakan 'statis' dalam kode fungsi internal secara eksplisit dengan '_s.' awalan, dan secara keseluruhan lebih mudah untuk dilihat dan dipahami.

kofifus
sumber
1

Ringkasan:

Di ES6/ ES 2015 classkata kunci diperkenalkan dengan statickata kunci yang disertakan . Perlu diingat bahwa ini adalah gula sintaksis atas model pewarisan prototypal yang diwujudkan oleh skrip. Kata statickunci berfungsi dengan cara berikut untuk metode:

class Dog {

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

}

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

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

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

Willem van der Veen
sumber
2
Dia meminta variabel statis, bukan fungsi statis.
Konrad Höffner
1

Saya menggunakan prototipe dan cara kerjanya:

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

Cat.COLLECTION_NAME = "cats";

atau menggunakan pengambil statis:

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

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

Jendela tingkat vars agak seperti statika dalam arti bahwa Anda dapat menggunakan referensi langsung dan ini tersedia untuk semua bagian dari aplikasi Anda

Bostone
sumber
3
Deskripsi yang jauh lebih baik dari vars tersebut adalah 'global', bukan statis.
Patrick M
0

Tidak ada yang namanya variabel statis dalam Javascript. Bahasa ini berorientasi objek berbasis prototipe, sehingga tidak ada kelas, tetapi prototipe dari mana objek "menyalin" sendiri.

Anda dapat mensimulasikan mereka dengan variabel global atau dengan prototyping (menambahkan properti ke prototipe):

function circle(){
}
circle.prototype.pi=3.14159
Gerardo
sumber
Metode ini berhasil, tetapi Anda mencemariFunction.prototype
Dan
@ Dan: Ini adalah pemahaman saya ini hanya untuk lingkaran dan bukan Fungsi. Setidaknya itulah yang coba diceritakan Chrome kepada saya: function circle() {}| circle.prototype| circle.prototype.pi = 3.14| circle.prototype| Function.prototype| Function.__proto__(jika itu yang Anda maksud)
Aktau
0

Bekerja dengan situs web MVC yang menggunakan jQuery, saya ingin memastikan tindakan AJAX dalam penangan peristiwa tertentu hanya dapat dieksekusi setelah permintaan sebelumnya selesai. Saya menggunakan variabel objek jqXHR "statis" untuk mencapai ini.

Diberikan tombol berikut:

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

Saya biasanya menggunakan IIFE seperti ini untuk pengendali klik saya:

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

Jika Anda ingin menggunakan prototipe maka ada caranya

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

Dengan melakukan ini, Anda akan dapat mengakses variabel penghitung dari setiap kejadian dan setiap perubahan pada properti akan segera tercermin !!

charlie
sumber