JavaScript 中的静态变量

Static variables in JavaScript

提问人:Rajat 提问时间:10/8/2009 最后编辑:MattRajat 更新时间:8/6/2022 访问量:855214

问:

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

JavaScript 变量 静态 闭包

评论

0赞 asghar 3/1/2019
我们可以定义带有“display:none”样式属性的标签或其他 HTML 标签,并为该值设置变量值并对该值进行操作。我们不要太辛苦了。
0赞 2/27/2020
我发现的最简单的解决方案是:根本不在类中定义静态变量。当您想使用静态变量时,只需在那里定义它,例如 .然后只需创建一个静态方法来返回静态成员,例如.然后你就可以从课外打电话来获取静态数据了!someFunc = () => { MyClass.myStaticVariable = 1; }static getStatic() { return MyClass.myStaticVariable; }MyClass.getStatic()
0赞 Salem 5/25/2022
我创建了自己的静态变量,通过向 HTML 元素添加新属性,我可以在脚本上的任何位置获取/更改该值btn.setAttribute( 'arr' , 0 )btn.getAttribute('arr')

答:

7赞 Andrew Hare 10/8/2009 #1

JavaScript 中最接近静态变量的是全局变量 - 这只是在函数或对象字面量范围之外声明的变量:

var thisIsGlobal = 1;

function foo() {
    var thisIsNot = 2;
}

您可以做的另一件事是将全局变量存储在对象字面量中,如下所示:

var foo = { bar : 1 }

然后像这样访问变量: .foo.bar

评论

0赞 veer7 6/26/2012
这个帮助我上传了多个文件.....var foo = {计数器:1};函数 moreFiles() { fileName = “File” + foo.counter; foo.counter = foo.counter + 1;
0赞 Bostone 10/8/2009 #2

从某种意义上说,窗口级变量有点像静态变量,您可以使用直接引用,并且这些变量可用于应用程序的所有部分

评论

3赞 Patrick M 11/29/2012
对此类变量的更好描述是“全局”,而不是静态。
600赞 Pascal MARTIN 10/8/2009 #3

你可以利用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.

这会得到同样类型的结果 -- 只不过,这一次,返回的是递增的值,而不是显示。

评论

63赞 Kip 9/24/2011
作为快捷方式,如果静态变量永远不会是 falsey(false、0、null 或空字符串),您可以这样做countMyself.counter = countMyself.counter || initial_value;
3赞 Tom Robinson 9/22/2013
稍微短一点,更清晰: (function() { var id = 0; function uniqueID() { return id++; }; })();
3赞 Sony Santos 12/9/2014
闭包中的计数器比 Firefox 中的类要快得多。jsperf.com/static-counter-in-class-vs-in-closure
1赞 Patrick Roberts 1/10/2018
if (!('counter' in countMyself)) { ... }似乎不那么冗长,语义更正确。并不是说大多数人会这样做,但是如果将语句明确定义为 ,则您的语句版本将无法检测到它的存在,例如 将导致 vs。ifcountMyself.counterundefinedcountMyself.counter = undefined!('counter' in countMyself) === false(typeof countMyself.counter == 'undefined') === true
1赞 SO Stinks 2/29/2020
对于顶部的函数版本,而不是更好,因此您不必对函数名称进行硬编码。countMyself.counterthis.counter
0赞 Gerardo 10/8/2009 #4

Javascript 中没有静态变量这样的东西。这种语言是基于原型的面向对象的,因此没有类,而是对象从中“复制”自己的原型。

您可以使用全局变量或原型设计(向原型添加属性)来模拟它们:

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

评论

0赞 Dan 10/11/2011
此方法有效,但您正在污染Function.prototype
0赞 Aktau 1/21/2013
@Dan:据我所知,这只是针对圆形而不是功能。至少这是Chrome试图告诉我的: | | | | | (如果这是你的意思)function circle() {}circle.prototypecircle.prototype.pi = 3.14circle.prototypeFunction.prototypeFunction.__proto__
956赞 Christian C. Salvadó 10/8/2009 #5

如果您来自基于类的静态类型面向对象语言(如 Java、C++ 或 C#),我假设您正在尝试创建与“类型”而不是实例关联的变量或方法。

使用“经典”方法和构造函数的示例可能会帮助您了解基本 OO JavaScript 的概念:

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在 MyClass 对象(这是一个函数)中定义,与其创建的实例无关,JavaScript 将函数视为第一类对象,因此作为一个对象,您可以为函数分配属性。

更新:ES6 引入了通过关键字声明类的功能。它是现有基于原型的继承的语法糖。class

static 关键字允许您轻松地在类中定义静态属性或方法。

让我们看看上面用 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"

评论

6赞 Dónal 11/12/2011
大概不等同于 OO 中的私有方法,因为它似乎可以在 MyClass 的实例上调用?你的意思是它是特权的,因为它可以访问?privilegedMethodprivateVariable
3赞 Ciro Santilli OurBigBook.com 6/22/2014
不能用于从“实例方法”访问静态变量?如果是,则值得将其添加到答案中。this.constructor
2赞 David Rodrigues 11/15/2014
您还可以在示例中提及静态函数
23赞 fullstacklife 3/20/2015
嗨,我不确定我是否同意这一行 // 所有实例共享的静态变量 'MyClass.staticProperty = “baz”; 对我来说,推断您可以从 'myInstance.staticProperty' 中找到 baz,当然你不能。
5赞 lindsaymacvean 11/10/2015
也许它应该读作,或者更正确地理解 OO 原则,静态属性实际上应该被定义为一个匿名函数,以便所有实例都访问一个变量,该变量也可以用 setter 进行更改。MyClass.prototype.staticProperty = "baz";MyClass.prototype.staticProperty = function () {return staticVar;}
41赞 gpilotino 11/6/2009 #6

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

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

评论

3赞 Dan 10/10/2011
据我所知,这种方法与 pascal MARTIN 的方式相比有一个(只有一个?)优势:你可以在匿名函数上使用它。这方面的一个例子就好了
30赞 Quolonel Questions 10/9/2013
arguments.callee已弃用。
0赞 user2173353 12/21/2016
我几乎一直在嘲笑JS,但似乎是一件好事。我想知道为什么黑客决定弃用这个...... :|callee
16赞 Nate 12/13/2011 #7

以下示例和解释来自 Nicholas Zakas 所著的《面向 Web 开发人员的 Professional JavaScript 2nd Edition》一书。这是我一直在寻找的答案,所以我认为在这里添加它会很有帮助。

(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

此示例中的构造函数可以访问私有变量名称,和方法也是如此。使用此模式,name 变量将变为静态变量,并将在所有实例中使用。这意味着调用一个实例会影响所有其他实例。调用或创建新实例会将 name 变量设置为新值。这会导致所有实例返回相同的值。PersongetName()setName()setName()setName()Person

评论

0赞 Ganesh Kumar 1/25/2012
looks 构造函数 + 原型(混合)
2赞 Ghola 3/18/2013
这会将 Person 对象放在全局命名空间中。不是我推荐的解决方案。
0赞 lindsaymacvean 11/10/2015
我不认为这是一个真正的静态变量,因为它在每个新对象中实例化的方式不同。静态对象应该在从父原型继承的所有对象中保持一致?
1赞 Nate 3/18/2016
@Ghola 这里的目的是解释如何创建静态变量。正确的命名空间和避免全局变量是一个单独的主题,这可能会增加答案的复杂性。由用户决定如何在不污染的情况下附加构造函数。如果这对尼古拉斯·扎卡斯来说足够好,那对我来说也足够好了。
0赞 Nate 3/18/2016
@lindsaymacvean 它是一个静态变量,因为单个值在所有实例之间共享。更改值是可以的。如果一个实例更改该值,则所有实例都将受到影响。它不太可能与上面的示例完全相同。允许在实例化期间设置该值只是为了表明它是可能的。一个更可能的用例是只让 getter 和 setter 或至少检查以确保它被设置为未定义以外的其他内容。
28赞 jim_zike_huang 2/29/2012 #8
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();
5赞 JoolzCheat 3/16/2012 #9

如果要创建全局静态变量:

var my_id = 123;

将变量替换为以下内容:

Object.defineProperty(window, 'my_id', {
    get: function() {
            return 123;
        },
    configurable : false,
    enumerable : false
});
-2赞 Parthiban Nagarajan 1/12/2013 #10
{
   var statvar = 0;
   function f_counter()
   {
      var nonstatvar = 0;
      nonstatvar ++;
      statvar ++;
      return statvar + " , " + nonstatvar;
   }
}
alert(f_counter());
alert(f_counter());
alert(f_counter());
alert(f_counter());

这只是我在某处学到的静态变量的另一种方法。

评论

7赞 Useless Code 3/29/2013
外层对不做任何事情;JavaScript 不是块范围的,而是函数范围的。正因为如此,你声明为一个全局的。如果不是 a,你用一个自调用的匿名函数包装它,它会更接近你认为那里发生的事情。{}statvar{}(function () {}());
0赞 Matt 5/5/2014
目前尚不清楚您在这里想向我们展示什么 - 以及它与问题的关系。请尽量更具描述性,并改进您的答案。
122赞 Chris 3/30/2013 #11

您可以通过 IIFE(立即调用的函数表达式)来执行此操作:

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

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

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

评论

27赞 6/2/2014
我想说这是在 JavaScript 中最惯用的方法。太糟糕了,由于其他方法,它没有得到太多的赞成票,这些方法可能更适合来自其他语言的人。
1赞 zendka 9/4/2019
我会使用“闭合”而不是“IIFE”来重新表述。
0赞 Bruno L. 6/19/2020
恭喜,绝对是最好的回复,简单就是美丽。即使很明显,我也可以扩展一下回应:var incr = (function (delta) { var i = 1; return function (delta) return i+=delta;} })();
2赞 blackcatweb 7/1/2021
我听说过它们被称为匿名自调用函数,也称为“ASIF”(“好像”你真的可以阅读它们:))。
8赞 Hemant 4/3/2013 #12

如果你想声明静态变量来在你的应用程序中创建常量,那么我发现以下是最简单的方法

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赞 Greg E 4/7/2013 #13

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

全局属性 sessionStorage 或 localStorage 允许在会话的生命周期内存储数据,或者无限期地存储数据,直到显式清除为止。这允许在页面/应用程序的所有窗口、框架、选项卡面板、弹出窗口等之间共享数据,并且比一个代码段中的简单“静态/全局变量”强大得多。

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

以“sessionStorage.mydata = anything”的形式轻松访问,并以类似的方式进行检索。看 “JavaScript: The Definitive Guide, Sixth Edition”,David Flanagan,ISBN:978-0-596-80552-4,第 20 章,第 20.1 节。这可以通过简单的搜索轻松下载为 PDF,也可以在您的 O'Reilly Safaribooks 订阅中下载(物有所值)。

45赞 Matt 9/10/2013 #14

我见过几个类似的答案,但我想提一下,这篇文章最能描述它,所以我想与你分享。

这里有一些从中获取的代码,我已经对其进行了修改,以获得一个完整的示例,希望它能为社区带来好处,因为它可以用作类的设计模板。

它还回答了您的问题:

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

根据该示例,您可以按如下方式访问静态属性/函数

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

对象属性/功能简称为:

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

请注意,在 podcast.immutableProp() 中,我们有一个闭包对 _somePrivateVariable 的引用保留在函数中。

您甚至可以定义 getter 和 setter。看看这个代码片段(其中是要声明属性的对象原型,是构造函数之外不可见的私有变量):dy

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

它通过 和 函数定义属性 - 如果您不指定 ,则该属性是只读的,无法修改(请注意,如果您尝试设置它,则不会收到错误,但它不起作用)。每个属性都有属性 , (允许在声明后更改) 和 (允许将其用作枚举器),这些属性是默认的。您可以在第 3 个参数中通过设置它们,例如 .d.yeargetsetsetwritableconfigurableenumerablefalsedefinePropertyenumerable: true

同样有效的是以下语法:

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

它定义了一个可读/可写的属性、一个只读属性和一个只写属性,通过这些属性可以被访问。abca

用法:

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

笔记:

为了避免在您忘记关键字时出现意外行为,我建议您将以下内容添加到函数中:newPodcast

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

现在,以下两个实例都将按预期工作:

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

“new”语句创建一个新对象并复制所有属性和方法,即

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"

另请注意,在某些情况下,使用构造函数中的语句返回自定义对象可能会很有用,该对象保护类内部依赖但需要公开的函数。本系列文章的第 2 章(对象)对此进行了进一步解释。returnPodcast

你可以这么说,并从继承。现在,如果您想向 Podcast 添加一种方法,该方法适用于之后的所有方法并已实例化,该怎么办?在这种情况下,请使用如下方法:abPodcastab.prototype

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

现在再次致电:ab

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

您可以在此处找到有关原型的更多详细信息。如果你想做更多的继承,我建议研究一下。


强烈建议阅读我上面提到的系列文章,它们还包括以下主题:

  1. 功能
  2. 对象
  3. 原型
  4. 在构造函数上强制执行 new
  5. 提升
  6. 自动插入分号
  7. 静态属性和方法

请注意,JavaScript 的自动分号插入“功能”(如 6 中所述)通常会导致代码中出现奇怪的问题。因此,我宁愿将其视为一个错误,而不是一个功能。

如果您想了解更多信息,这里有一篇关于这些主题的非常有趣的 MSDN 文章,其中一些主题在那里描述提供了更多详细信息。

有趣的是 MDN JavaScript 指南中的那些文章(也涵盖了上面提到的主题):

如果你想知道如何在 JavaScript 中模拟 c# out 参数(如 ),你可以在这里找到示例代码。DateTime.TryParse(str, out result)


那些使用 IE(除非使用 F12 打开开发人员工具并打开控制台选项卡,否则 IE 没有 JavaScript 控制台)的用户可能会发现以下代码片段很有用。它允许您按照上述示例中使用的方式使用。只需将其插入函数之前即可。console.log(msg);Podcast

为方便起见,下面是上述代码在一个完整的单个代码片段中:

let console = { log: function(msg) {  
  let canvas = document.getElementById("log"), br = canvas.innerHTML==="" ? "" : "<br/>";
  canvas.innerHTML += (br + (msg || "").toString());
}};

console.log('For details, see the explaining text');

function Podcast() {

  // with this, you can instantiate without new (see description in text)
  if (false === (this instanceof Podcast)) {
    return new Podcast();
  }

  // private variables
  var _somePrivateVariable = 123;

  // object properties
  this.title = 'Astronomy Cast';
  this.description = 'A fact-based journey through the galaxy.';
  this.link = 'http://www.astronomycast.com';

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


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

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

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

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

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

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"

Podcast.prototype.titleAndLink = function() {
    return this.title + " [" + this.link + "]";
};
    
console.log(a.titleAndLink()); // "a [http://www.astronomycast.com]"
console.log(b.titleAndLink()); // "An Astronomy Cast [http://www.astronomycast.com]"
<div id="log"></div>


笔记:

  • 关于JavaScript编程的一些好的技巧、提示和建议,你可以在这里(JavaScript最佳实践)和那里('var'与'let')找到。还推荐这篇关于隐式类型转换(强制)的文章。

  • 使用类并将其编译为 JavaScript 的一种便捷方法是 TypeScript。 这是一个游乐场,您可以在其中找到一些示例,向您展示它是如何工作的。 即使您目前没有使用 TypeScript,也可以查看一下,因为您可以在并排视图上将 TypeScript 与 JavaScript 结果进行比较。大多数示例都很简单,但还有一个 Raytracer 示例,您可以立即试用。 我建议特别查看“使用类”、“使用继承”和“使用泛型”示例,方法是在组合框中选择它们 - 这些是您可以在 JavaScript 中立即使用的好模板。Typescript 与 Angular 一起使用

  • 为了在 JavaScript 中实现局部变量、函数等的封装,我建议使用如下模式(JQuery 使用相同的技术):

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

当然,您可以 - 并且应该 - 将脚本代码放在一个单独的文件中;这只是内联编写的,以保持示例简短。*.js

此处更详细地介绍了自调用函数(也称为 IIFE = 立即调用的函数表达式)。

4赞 Luca Reghellin 11/24/2013 #15

要在此处压缩所有类概念,请测试以下内容:

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

好吧,另一种查看这些事情最佳实践的方法,就是看看 coffeescript 是如何翻译这些概念的。

#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);
0赞 Todd L 3/13/2014 #16

使用使用 jQuery 的 MVC 网站时,我希望确保某些事件处理程序中的 AJAX 操作只能在上一个请求完成后执行。我使用一个“静态”jqXHR 对象变量来实现这一点。

给定以下按钮:

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

我通常使用这样的 IIFE 作为我的点击处理程序:

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赞 charlie 5/9/2014 #17

如果你想使用原型,那么有一种方法可以

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

这样做,您将能够从任何实例访问计数器变量,并且属性中的任何更改都将立即反映出来!

-3赞 Uthaiah 7/15/2014 #18

当我看到这个时,我记得 JavaScript 闭包..这是我是如何做到的..

        function Increment() {
            var num = 0; // Here num is a private static variable
            return function () {
                return ++num;
            }
        }

        var inc = new Increment();
        console.log(inc());//Prints 1
        console.log(inc());//Prints 2
        console.log(inc());//Prints 3
7赞 funroll 2/8/2015 #19

还有其他类似的答案,但没有一个能吸引我。这是我最终得到的:

var nextCounter = (function () {
  var counter = 0;
  return function() {
    var temp = counter;
    counter += 1;
    return temp;
  };
})();
31赞 Max Heiber 3/27/2015 #20

更新答案:

ECMAScript 6 中,您可以使用关键字创建静态函数: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

ES6 类没有为静态引入任何新的语义。你可以在 ES5 中做同样的事情,如下所示:

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

您可以分配给 因为在 JavaScript 中函数是对象的属性。Foo

评论

0赞 6/22/2015
Foo.bar;返回分配给它的函数,而不是注释所暗示的函数返回的字符串。
0赞 Wilt 6/20/2016
您能否在这两个示例中添加一些有关如何设置(覆盖)静态值的信息?
1赞 Max Heiber 6/22/2016
@Wilt在这两种情况下,“静态”属性都只是函数上的一个属性,因此您可以设置它并覆盖它,就像在 JavaScript 中设置任何其他属性一样。在这两种情况下,您都可以将 的属性设置为如下所示:barFoo3Foo.bar = 3;
0赞 Ciro Santilli OurBigBook.com 8/5/2019
ES6 具体问题:stackoverflow.com/questions/28445693/...
0赞 lindsaymacvean 11/11/2015 #21

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

面向对象编程实际上有两种不同的风格,一种是“基于类的”(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 方法)中,从而从 Global 命名空间中隐藏构造函数

 $(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。在不同的场景中,我们可以停止对子对象的任何更改,也可以在构造函数中设置 setter 和 getter 方法并访问闭包,这两者都具有相关的复杂性。Object.freeze(obj)

在我看来,基于类的“静态属性”概念与这种 Javascript 实现之间并没有完美的类比。因此,我认为从长远来看,使用对 Javascript 更友好的不同 Code Pattern 可能会更好。例如中央数据存储或缓存,甚至是专用的帮助程序对象来保存所有必要的静态变量。

0赞 danielson317 2/13/2016 #22

我没有在任何答案中看到这个想法,所以只是将其添加到列表中。如果它是重复的,请告诉我,我会删除它并投票给另一个。

我在我的网站上创建了一种超级全球化。由于我在每个页面加载时都加载了几个 js 文件,并且仅在某些页面上加载了数十个其他 js 文件,因此我将所有“全局”函数放入一个全局变量中。

在我包含的第一个“全局”文件的顶部是声明

var cgf = {}; // Custom global functions.

然后我研究了几个全局辅助函数

cgf.formBehaviors = function()
{
    // My form behaviors that get attached in every page load.
}

然后,如果我需要一个静态变量,我只需将其存储在范围之外,例如在文档准备之外或行为附件之外。(我使用jquery,但它应该在javascript中工作)

cgf.first = true;
$.on('click', '.my-button', function()
{
    // Don't allow the user to press the submit twice.
    if (cgf.first)
    {
        // first time behavior. such as submit
    }
    cgf.first = false;
}

这当然是全局的,而不是静态的,但是由于它在每次页面加载时都会重新初始化,因此它实现了相同的目的。

-1赞 Cubocicloide 2/24/2016 #23

你可以这样想。放入一个标签并设置其 .<body></body><p id='staticVariable'></p>visibility: hide

当然,您可以使用 jquery 管理上一个标签中的文本。实际上,这个标签会成为你的静态变量。

0赞 Satyapriya Mishra 4/1/2016 #24

在 JavaScript 中,没有术语或关键字 static,但我们可以将此类数据直接放入函数对象中(就像在任何其他对象中一样)。

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
6赞 Sнаđошƒаӽ 7/31/2016 #25

您可以在 JavaScript 中创建一个静态变量,如下所示。这是静态变量。count

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

您可以使用函数或任何实例为静态变量赋值:Person

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

评论

0赞 ArunDhwaj IIITH 4/19/2018
这是在 JavaScript 中声明静态变量并访问它的好方法之一。
0赞 Martin Wantke 10/25/2016 #26

对于私有静态变量,我是这样发现的:

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赞 Bart 11/15/2016
这不是一个有效的解决方案:实际上被创建为全局对象(即在浏览器中使用时作为成员)。因此,虽然它是静态的,但它不是私有的,也不属于 ._privateStaticwindowClass
0赞 himanshu 11/10/2016 #27

试试这个:

如果我们定义一个属性并覆盖它的 getter 和 setter 以使用 Function Object 属性,那么理论上你可以在 javascript 中拥有一个静态变量

例如:

function Animal() {
    if (isNaN(this.totalAnimalCount)) {
        this.totalAnimalCount = 0;
    }
    this.totalAnimalCount++;
};
Object.defineProperty(Animal.prototype, 'totalAnimalCount', {
    get: function() {
        return Animal['totalAnimalCount'];
    },
   set: function(val) {
       Animal['totalAnimalCount'] = val;
   }
});
var cat = new Animal(); 
console.log(cat.totalAnimalCount); //Will produce 1
var dog = new Animal();
console.log(cat.totalAnimalCount); //Will produce 2 and so on.

0赞 prosti 2/8/2017 #28

在 JavaScript 中,一切都是原始类型或对象。 函数是对象 — (键值对)。

创建函数时,将创建两个对象。一个对象表示函数本身,另一个对象表示函数的原型。

从这个意义上说,函数基本上是一个具有以下属性的对象:

function name, 
arguments length 
and the functional prototype.

那么在哪里设置静态属性: 两个位置,一个在函数对象内部,要么在函数原型对象内部。

下面是一个代码片段,它使用 JavaScript 关键字创建该结尾甚至实例化两个实例。new

function C () { // function
  var privateProperty = "42";  
  this.publicProperty = "39";  
  
  this.privateMethod = function(){ 
   console.log(privateProperty);
  };
}

C.prototype.publicMethod = function () {    
  console.log(this.publicProperty);
};

C.prototype.staticPrototypeProperty = "4";
C.staticProperty = "3";


var i1 = new C(); // instance 1
var i2 = new C(); // instance 2

i1.privateMethod();
i1.publicMethod();

console.log(i1.__proto__.staticPrototypeProperty);
i1.__proto__.staticPrototypeProperty = "2";
console.log(i2.__proto__.staticPrototypeProperty);

console.log(i1.__proto__.constructor.staticProperty);
i1.__proto__.constructor.staticProperty = "9";
console.log(i2.__proto__.constructor.staticProperty);

主要思想是实例和使用相同的静态属性。i1i2

评论

0赞 att 1/21/2021
__proto__.staticVariable在我的 nodejs 应用程序中为我工作。
15赞 Automatico 2/23/2017 #29

如果您使用的是新的类语法,那么您现在可以执行以下操作:

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

    console.log(MyClass.myStaticVariable);

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

这有效地在 JavaScript 中创建一个静态变量。

评论

0赞 Indolering 7/12/2017
这在构建静态实用程序类时很有用!
1赞 trincot 4/16/2018
但现在的问题是,如何持久化一个值,并允许使用setter对其进行更改。需要闭包或在类构造之外定义的属性。MyClass
0赞 Ciro Santilli OurBigBook.com 8/5/2019
相关新闻: stackoverflow.com/questions/28445693/...
9赞 COil 3/24/2017 #30

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

以下示例显示了如何使用 .合成器:staticVarClassNamevar

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
2赞 Kerim Tim. 4/8/2017 #31

在 JavaScript 中,变量默认是静态的。示例

var x = 0;

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

setInterval(draw, 1000);

x 的值每 1000 毫秒
递增 1,它将打印 1,2,3,依此类推

评论

4赞 challet 12/1/2019
这是一个不同的情况。您的示例是关于范围的。
1赞 Yash 8/24/2017 #32

函数的 / 类只允许其对象范围使用单个构造函数。函数提升、声明和表达式

  • 使用 Function 构造函数创建的函数不会为其创建上下文创建闭包;它们始终在全局范围内创建。

      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)
    

闭包 - 闭包的副本与保留的数据一起使用。

  • 每个闭包的副本都创建到具有自己的自由值或引用的函数中,每当您在另一个函数中使用函数时,都会使用闭包。
  • JavaScript 中的闭包就像通过 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
    

ES5 函数类:使用 Object.defineProperty ( O, P, Attributes )

Object.defineProperty() 方法直接在对象上定义新属性,或修改对象上的现有属性,然后返回该对象。

使用''创建了一些方法,以便每个人都可以轻松理解函数类。

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

下面的代码片段是测试每个实例都有自己的副本的实例成员和公共静态成员。

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

静态方法调用直接在类上进行,不能在类的实例上调用。但是,您可以从实例内部实现对静态成员的调用。

使用语法:

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

ES6 类:ES2015 类是基于原型的 OO 模式的简单糖。使用单个方便的声明式表单可以使类模式更易于使用,并鼓励互操作性。类支持基于原型的继承、超级调用、实例和静态方法以及构造函数。

示例:请参阅我之前的帖子。

0赞 kofifus 8/30/2017 #33

我经常使用静态函数变量,很遗憾 JS 没有内置机制。我经常看到在外部作用域中定义变量和函数的代码,即使它们只是在一个函数中使用。这很丑陋,容易出错,只是自找麻烦......

我想出了以下方法:

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

这将向所有函数添加一个“statics”方法(是的,放松一下),调用时,它将向函数对象添加一个空对象 (_statics) 并返回它。如果提供了 init 函数,_statics 将设置为 init() result。

然后,您可以执行以下操作:

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

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

将其与另一个正确答案的 IIFE 进行比较,它的缺点是在每次函数调用时添加一个赋值和一个 if,并向函数添加一个“_statics”成员,但是有一些优点:参数位于顶部,而不是在内部函数中,在内部函数代码中使用“static”是带有“_s”前缀的显式, 而且总体上更易于查看和理解。

7赞 Dimitris Fasarakis Hilliard 2/8/2018 #34

除此之外,目前还有一份关于ECMA提案的草案(第2阶段提案),该草案在类中引入了公共字段。(考虑了私有字段static)

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

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

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

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

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

您可以在 proposal-static-class-features 中跟踪新提案。


目前,babel 通过您可以使用的 transform 类属性插件来支持此功能。此外,尽管仍在进行中,但 V8 正在实现它

9赞 GetFree 4/26/2018 #35

在 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
0赞 Willem van der Veen 8/31/2018 #36

总结:

在 /ES 2015 中,关键字是随附关键字引入的。请记住,这是 javavscript 所体现的原型继承模型的语法糖。对于方法,关键字的工作方式如下:ES6classstaticstatic

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赞 Konrad Höffner 9/27/2018
他要求一个静态变量,而不是一个静态函数。
-1赞 User 11/15/2018 #37

我通常使用这种方法有两个主要原因:

如果我想存储函数本地值,我会使用“Local.x”、“Local.y”、“Local.TempData”等......!

如果我想存储函数静态值,我会使用“Static.o”、“Static.Info”、“Static.count”等......!

[Update2]:方法相同,但使用IIFE方法!

[Update1]:函数的“静态”和“本地”对象通过预编辑脚本自动创建!

0赞 EliuX 8/22/2019 #38

我使用了原型,它的工作方式是:

class Cat {
  constructor() {
    console.log(Cat.COLLECTION_NAME);
  }
}

Cat.COLLECTION_NAME = "cats";

或使用静态 getter:

class Cat {
  constructor() {
    console.log(Cat.COLLECTION_NAME);
  }

  static get COLLECTION_NAME() {
    return "cats"
  }
}
1赞 vkarpov15 12/25/2019 #39

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

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

MyClass.myStaticFunction(); // 42

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

class MyClass {}

MyClass.myStaticProperty = 42;

MyClass.myStaticProperty; // 42

最后要注意:在使用具有继承功能的静态对象时要小心 - 所有继承的类共享对象的同一副本

0赞 realmag777 1/15/2020 #40

我有通用方法:

  • 创建对象,如下所示:stat_flags = {};
  • 将它与动态添加字段一起使用:flags.popup_save_inited = true;
  • 下次问对象中是否有你需要的标志,并做你的逻辑

例:

class ACTGeneratedPages {
    constructor(table_data, html_table_id) {
        this.flags = {};//static flags for any processes

        //any your code here

    }

    call_popup(post_id) {

        let _this = this;
        document.getElementById('act-popup-template').style.display = 'block';

        if (!this.flags.popup_save_inited) {//second time listener will not be attached
            document.querySelector('.act-modal-save').addEventListener('click', function (e) {
                //saving data code here
                return false;
            });
        }

        this.flags.popup_save_inited = true;//set flag here
    }

}
0赞 vkarpov15 4/3/2020 #41

ES6 类支持静态函数,其行为与其他面向对象语言中的静态函数非常相似:

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

typeof MyClass.myFunction; // 'function'
MyClass.myFunction(); // 42

一般的静态属性仍然是第 3 阶段的提议,这意味着你需要 Babel 的第 3 阶段预设才能使用它们。但是使用 Babel,您可以这样做:

class MyClass {
  static answer = 42;
}

MyClass.answer; // 42
8赞 JΛYDΞV 6/21/2021 #42

2021年更新

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

自 2021 年 4 月起,TC39 将关键字移至 Stage-4 语言功能。将 JS 功能制作成一套官方的 JS 语言功能花了很长时间,然而,等待是由于缺乏浏览器支持;主要浏览器现在支持 static 关键字,以及公共静态字段和私有静态字段的开放季节。STATICstatic



下面是实现静态 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 存储库 Static-Fields


要了解有关此新 JS 语言功能实现的更多信息(请单击此处)。
要了解有关该功能本身的更多信息,以及查看演示用于静态字段的语法的示例(单击此处)。

评论

0赞 Heath Raftery 9/26/2021
好的,但要清楚的是,这显式地添加了静态功能,对吗?我点击了链接,没有提到“静态变量”。它们列出了静态公共字段、私有方法和私有字段。它们都与静态变量不同。所以这里的旧答案仍然有效吗?
0赞 JΛYDΞV 9/26/2021
@HeathRaftery 不,你说得对,我明白我做了什么。我应该输入“静态字段”,甚至是“静态类成员”,然后我写了“静态变量”。你可以编辑它,我的意思是你不必这样做,但如果你这样做,你会是对的。
0赞 Mr. Doge 9/16/2021 #43

您可以在声明静态变量后重新分配函数

function IHaveBeenCalled() {
  console.log("YOU SHOULD ONLY SEE THIS ONCE");
  return "Hello World: "
}
function testableFunction(...args) {
  testableFunction=inner //reassign the function
  const prepend=IHaveBeenCalled()
  return inner(...args) //pass all arguments the 1st time
  function inner(num) {
    console.log(prepend + num);
  }
}
testableFunction(2) // Hello World: 2
testableFunction(5) // Hello World: 5

这使用哪个更慢,有没有办法第一次使用父函数的作用域而不是传递所有参数?...args


我的用例:

function copyToClipboard(...args) {
  copyToClipboard = inner //reassign the function
  const child_process = require('child_process')
  return inner(...args) //pass all arguments the 1st time
  function inner(content_for_the_clipboard) {
    child_process.spawn('clip').stdin.end(content_for_the_clipboard)
  }
}

如果要在作用域之外使用,可以将其分配给child_processcopyToClipboard

function copyToClipboard(...args) {
  copyToClipboard = inner //reassign the function
  copyToClipboard.child_process = require('child_process')
  return inner(...args) //pass all arguments the 1st time
  function inner(content_for_the_clipboard) {
    copyToClipboard.child_process.spawn('clip').stdin.end(content_for_the_clipboard)
  }
}