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


当前回答

您可以使用arguments.callee存储“静态”变量(这在匿名函数中也很有用):

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

其他回答

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

面向对象编程实际上有两种不同的风格,一种是基于类的(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更友好的不同代码模式可能会更好。比如一个中央数据存储或缓存,甚至一个专用的帮助对象来保存所有必要的静态变量。

您可以使用static关键字在JavaScript中定义静态函数:

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

MyClass.myStaticFunction(); // 42

在撰写本文时,您仍然无法在类中定义静态财产(函数除外)。静态财产仍然是第三阶段的建议,这意味着它们还不是JavaScript的一部分。然而,没有什么可以阻止您像分配给任何其他对象一样简单地分配给类:

class MyClass {}

MyClass.myStaticProperty = 42;

MyClass.myStaticProperty; // 42

最后一点:小心使用带有继承的静态对象-所有继承的类共享对象的相同副本。

摘要:

在ES6/ES 2015中,class关键字与附带的静态关键字一起引入。请记住,这是javavscript所体现的原型继承模型的语法糖。static关键字对方法的工作方式如下:

类狗{静态树皮(){console.log('wof');}//类是隐藏的函数对象//树皮方法位于Dog函数对象上makeSound(){console.log('bark');}//makeSound位于Dog.prototype对象上}//要创建静态变量,只需在类的原型上创建一个属性Dog.prototype.breed=“Pitbull”;//因此,要定义静态属性,我们不需要“static”关键字。const蓬松=新狗();const vicky=新狗();控制台.日志(绒毛.品种,vicky.品种);//更改静态变量会更改所有对象上的静态变量Dog.prototype.breed=“梗”;控制台.日志(绒毛.品种,vicky.品种);

在Javascript中有4种模拟函数局部静态变量的方法。

方法1:使用函数对象财产(在旧浏览器中受支持)

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

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

方法2:使用闭包,变体1(旧浏览器支持)

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

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

方法3:使用闭包,变体2(在旧浏览器中也支持)

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

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

方法4:使用闭包,变体3(需要支持EcmaScript 2015)

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

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

严格模式的方法4

'use strict'
{
    let staticVar = 0 ;
    var someFunc4 = function(){
        alert(++staticVar) ;
    } ;
}

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

关于ECMAScript 2015引入的类。其他答案并不完全清楚。

下面是一个示例,演示如何使用ClassName.var synthax创建静态var-staticVar:

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

为了访问静态变量,我们使用.constructor属性,该属性返回对创建类的对象构造函数的引用。我们可以在两个创建的实例上调用它:

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