如何在Javascript中创建静态变量?


当前回答

除其他内容外,目前还有一个关于ECMA提案的草案(第2阶段提案),它在类中引入了静态公共字段。(考虑了私人领域)

使用提案中的示例,建议的静态语法如下所示:

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

并等同于其他人强调的以下内容:

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

然后,您可以通过CustomDate.epoch访问它。

您可以在提案静态类特性中跟踪新提案。


目前,babel通过您可以使用的转换类财产插件支持此功能。此外,尽管仍在进行中,V8正在实现它。

其他回答

您可以利用JS函数也是对象这一事实,这意味着它们可以具有财产。

例如,引用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);
}

如果多次调用该函数,您将看到计数器正在递增。

这可能是一个比用全局变量替换全局命名空间更好的解决方案。

下面是基于闭包的另一种可能的解决方案:在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.

这会得到相同的结果——只是这次返回的是递增的值,而不是显示。

2021更新

在2021,您可以简单地使用static关键字

截至2021 4月,TC39将STATIC关键字移至第4阶段语言功能。将静态JS特性变成一组正式的JS语言特性需要很长时间,然而,等待的原因是缺乏浏览器支持;现在,主流浏览器支持static关键字,并支持公共静态字段和私有静态字段的开放季节。



下面是实现静态JavaScript类成员的新方法的一般示例

class ColorFinder {
  static #red = "#ff0000";
  static #green = "#00ff00";
  static #blue = "#0000ff";
  
  static colorName(name) {
    switch (name) {
      case "red": return ColorFinder.#red;
      case "blue": return ColorFinder.#blue;
      case "green": return ColorFinder.#green;
      default: throw new RangeError("unknown color");
    }
  }
  
  // Somehow use colorName
}

以上示例取自TC39存储库,静态字段



要了解更多关于这个新的JS语言特性的实现(单击此处)。

阅读更多关于该特性本身的信息,以及演示静态字段语法的示例(单击此处)。

还有另一种方法,它解决了我浏览这个线程后的需求。这完全取决于您想要使用“静态变量”实现什么。

全局属性sessionStorage或localStorage允许在会话的生命周期内存储数据,或在明确清除之前存储不确定的更长时间。这允许在页面/应用程序的所有窗口、框架、选项卡面板、弹出窗口等之间共享数据,并且比一个代码段中的简单“静态/全局变量”功能强大得多。

它避免了顶级全局变量(如Window.myglobal)的范围、生存期、语义、动态等方面的所有麻烦。不知道它有多高效,但这对于以适度速度访问的少量数据来说并不重要。

轻松访问为“sessionStorage.mydata=anything”,并以类似方式检索。看见“JavaScript:最终指南,第六版”,David Flanagan,ISBN:978-0-596-80552-4,第20章,第20.1节。通过简单的搜索,或在O’Reilly Safaribooks订阅(价值黄金)中,可以轻松下载为PDF格式。

所以我从其他答案中看到的是,它们没有解决面向对象编程中静态属性的基本架构要求。

面向对象编程实际上有两种不同的风格,一种是基于类的(C++、C#、Java等),另一种是原型的(Javascript)。在基于类的语言中,“静态属性”应该与类关联,而不是与实例化对象关联。这个概念实际上在Javascript这样的原型语言中更为直观,因为您只需将属性指定为父原型的值即可。

function MyObject() {};
MyObject.prototype.staticAttribute = "some value";

并从从该构造函数实例化的每个对象访问它,就像这样。。。

var childObject1 = new MyObject(); // Instantiate a child object
var childObject2 = new MyObject(); // Instantiate another child object
console.log(childObject.staticAttribute); // Access the static Attribute from child 1
console.log(childObject.staticAttribute); // Access the static Attribute from child 2

现在,如果您继续更改MyObject.prototype.staticAttribute,则更改将级联到立即继承它的子对象。

然而,有一些“陷阱”可能会严重破坏此属性的“静态”特性,或者只留下安全漏洞。。。

首先,确保通过将构造函数封装在另一个函数(如jQuery ready方法)中,从全局命名空间中隐藏构造函数

 $(document).ready(function () {
    function MyObject() {
        // some constructor instructions
    };
    MyObject.prototype.staticAttribute = "some value";
    var childObject = new MyObject(); // instantiate child object
    console.log(childObject.staticAttribute); // test attribute
});

第二,也是最后一点,即使您这样做,该属性仍然可以从您自己的脚本的任何其他部分进行编辑,因此可能是代码中的错误覆盖了某个子对象的属性,并将其从父原型分离,因此如果您更改父属性,它将不再级联并更改子对象的静态属性。看看这个jsfiddle。在不同的场景中,我们可以使用Object.freeze(obj)来停止对子对象的任何更改,也可以在构造函数中设置setter和getter方法并访问闭包,这两者都具有相关的复杂性。

在我看来,“静态属性”的基于类的思想和这个Javascript实现之间似乎没有完美的相似之处。因此,我认为从长远来看,使用一种对Javascript更友好的不同代码模式可能会更好。比如一个中央数据存储或缓存,甚至一个专用的帮助对象来保存所有必要的静态变量。

除其他内容外,目前还有一个关于ECMA提案的草案(第2阶段提案),它在类中引入了静态公共字段。(考虑了私人领域)

使用提案中的示例,建议的静态语法如下所示:

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

并等同于其他人强调的以下内容:

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

然后,您可以通过CustomDate.epoch访问它。

您可以在提案静态类特性中跟踪新提案。


目前,babel通过您可以使用的转换类财产插件支持此功能。此外,尽管仍在进行中,V8正在实现它。