JavaScript中的静态变量


716

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


我们可以使用“ dispaly:none”样式属性定义标签或其他html标签,并为此值设置变量值并对该值进行操作。我们不要努力。
asghar

我找到的最简单的解决方案:根本不要在类中定义静态变量。当您想使用静态变量时,只需在其中定义即可,例如someFunc = () => { MyClass.myStaticVariable = 1; }。然后,只需创建一个静态方法即可返回静态成员,例如static getStatic() { return MyClass.myStaticVariable; }。然后,您可以MyClass.getStatic()从类外部调用以获取静态数据!
像素

Answers:


862

如果您来自基于类的静态类型的面向对象的语言(例如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"


5
大概privilegedMethod不等同于OO中的私有方法,因为似乎可以在MyClass的实例上调用它?您是说它可以访问privateVariable吗?
–Dónal

3
不能this.constructor用于从“实例方法”访问静态变量吗?如果是,则值得将其添加到答案中。
Ciro Santilli冠状病毒审查六四事件法轮功

1
您还可以在示例中提及静态函数
David Rodrigues

18
嗨,我不确定我是否同意这一行//所有实例'MyClass.staticProperty =“ baz”;'共享的静态变量 对来说,您可以从“ myInstance.staticProperty”中找到baz,但您当然找不到。
fullstacklife 2015年

5
也许应该阅读MyClass.prototype.staticProperty = "baz";或更正确地理解OO原理,静态属性实际上应该定义为匿名函数MyClass.prototype.staticProperty = function () {return staticVar;},以便所有实例访问单个变量,也可以使用setter对其进行更改。
lindsaymacvean

535

您可能会利用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.

可以得到相同的结果-这次不同的是,返回的是增量值,而不是显示出来。


50
作为一种快捷方式,countMyself.counter = countMyself.counter || initial_value;如果静态变量永远不会为假(false,0,null或空字符串),则可以这样做
Kip

3
稍短和清晰:(function(){var id = 0; function uniqueID(){return id ++;};})();
汤姆·罗宾逊

3
关闭计数器比Firefox中的类要快得多。jsperf.com/static-counter-in-class-vs-in-closure
Sony Santos

使用===typeof支票否则你会得到一些奇怪的胁迫回事。
2015年

@SonySantos您的测试显示了与Firefox 40相反的情况
bartolo-otrit 2015年

96

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

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

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

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

21
我想说这是在JavaScript中最惯用的方式。不幸的是,由于其他方法可能没有更多的赞誉,而其他人可能更喜欢这种方法。

1
我会改用“ closure”而不是“ IIFE”。
zendka '19

39

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

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

3
据我了解,此方法比pascal PARTI MARTIN的方法有一个(只有一个?)优点:您可以在匿名函数上使用它。一个很好的例子
丹,

27
arguments.callee不推荐使用。
Quolonel问题

我一直都在嘲笑JS,但是callee似乎很高兴。我想知道为什么他们决定不赞成这种做法...:|
user2173353 '16

34

我已经看到了两个类似的答案,但是我想提一下,这篇文章最能说明问题,因此,我想与您分享。

这是从中获取的一些代码,我对其进行了修改,以获取一个完整的示例,该示例有望使社区受益,因为它可以用作类的设计模板。

它还可以回答您的问题:

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。看一下以下代码片段(d您要为其声明属性的对象的原型是哪里,它y是在构造函数之外不可见的私有变量):

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

d.year通过getset函数定义属性-如果您未指定set,则该属性为只读且无法修改(请注意,如果您尝试设置它,将不会收到错误消息,但它无效)。每个属性都有属性writableconfigurable(允许在声明后进行更改)和enumerable(允许将其用作枚举器),它们都是默认属性false。您可以通过defineProperty在第3个参数中设置它们,例如enumerable: true

以下语法也是有效的:

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

它定义了一个可读/可写属性a,一个只读属性b和一个只写属性c,通过它们a可以访问该属性。

用法:

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

笔记:

为了避免在忘记new关键字的情况下发生意外行为,建议您在函数中添加以下内容Podcast

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

还要注意,在某些情况下,使用return构造函数中的语句Podcast返回自定义对象保护类是有用的,该对象保护类内部依赖但需要公开的函数。在系列文章的第2章(对象)中对此进行了进一步说明。

您可以这样说ab继承自Podcast。现在,如果您想向Podcast添加一种方法,该方法适用于所有实例a并且b实例化了?在这种情况下,请使用.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. 强制执行构造函数的新功能
  5. 吊装
  6. 自动分号插入
  7. 静态属性和方法

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

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

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

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


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

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


笔记:

  • 通常,您可以在此处(JavaScript最佳实践)那里(“ var”与“ let”)找到有关JavaScript编程的一些好的技巧,提示和建议。还推荐使用 有关隐式类型转换(强制)的本文

  • 使用类并将其编译为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 =立即调用函数表达式)在此处进行了详细说明


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

28

更新的答案:

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

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


Foo.bar;返回分配给它的函数,而不是您的注释所暗示的函数返回的字符串。

您可以在这两个示例中添加一些有关如何设置(覆盖)静态值的信息吗?
威尔特

1
在两种情况下,@ Wilt都是一个“静态”属性,只是该函数的一个属性,因此您可以对其进行设置和覆盖,就像在JavaScript中使用其他任何属性一样。在这两种情况下,你可以设置bar的属性Foo,以3这样的:Foo.bar = 3;
最大Heiber


16

以下示例和说明摘自Nicholas Zakas撰写的《面向Web开发人员的专业JavaScript第二版》一书。这是我一直在寻找的答案,因此我认为将其添加到此处会有所帮助。

(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

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


看起来构造函数+原型(混合型)
Ganesh Kumar

2
这会将Person对象放置在全局名称空间中。不是一个解决方案,我建议。
Ghola 2013年

我认为这不是真正的静态变量,因为每个新对象的实例化方式都不相同。静态对象在从父原型继承的所有对象之间应该是一致的吗?
lindsaymacvean 2015年

1
@Ghola这里的目的是解释如何创建静态变量。正确的命名空间和避免使用全局变量是一个单独的主题,可能会增加答案的复杂性。由用户决定如何附加构造函数而不污染。如果对尼古拉斯·扎卡斯(Nicholas Zakas)足够好,对我也足够。
Nate

@lindsaymacvean这是一个静态变量,因为单个值在所有实例之间共享。可以更改值。如果一个实例更改了值,则所有实例都会受到影响。它不可能与上面的示例完全一样地使用。允许在实例化期间设置该值只是为了表明它是可能的。一种更可能的用例是仅具有getter和setter或至少进行检查以确保将其设置为未定义的内容。
Nate

15

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

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

    console.log(MyClass.myStaticVariable);

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

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


这在构建静态实用程序类时很有用!
Indolering'7

1
但是现在的问题是,如何保留一个值并允许使用setter对其进行更改。将需要闭包或MyClass在类构造之外定义的属性。
Trincot


8

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

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;

8

关于classECMAScript 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

7

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

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

7

除了其余的,目前还有一个草稿(关于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 可以使用您可以使用的转换类属性插件来支持此功能。此外,尽管仍在进行中,但仍在V8实施它


6

您可以像下面这样在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

这是声明静态变量并在JavaScript中访问它的好方法之一。
ArunDhwaj IIITH

5

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

var my_id = 123;

将变量替换为以下内容:

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

4

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

var thisIsGlobal = 1;

function foo() {
    var thisIsNot = 2;
}

您可以做的另一件事是将全局变量存储在这样的对象文字中:

var foo = { bar : 1 }

然后访问variabels这样的:foo.bar


这个帮助我上传了多个文件..... var foo = {counter:1}; 函数moreFiles(){fileName =“ File” + foo.counter; foo.counter = foo.counter +1;
veer7 2012年

4

要在这里压缩所有类的概念,请对此进行测试:

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

4

在JavaScript中,默认情况下变量是静态的。范例

var x = 0;

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

setInterval(draw, 1000);

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


2
那是另一回事。您的示例涉及范围。
challet

4

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

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

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

可以通过“ sessionStorage.mydata = any”轻松访问,并且可以类似地进行检索。参见“ JavaScript:权威指南,第六版”,David Flanagan,ISBN:978-0-596-80552-4,第20章,第20.1节。通过简单的搜索即可轻松将其下载为PDF,也可以通过O'Reilly Safaribooks订阅轻松下载(价值不菲)。


2

函数的/类仅允许将单个构造函数用于其对象范围。 Function Hoisting, declarations & expressions

  • 使用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模式的简单补充。具有单个方便的声明形式使类模式更易于使用,并鼓励了互操作性。类支持基于原型的继承,超级调用,实例以及静态方法和构造函数。

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


2

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

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

2

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

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

MyClass.myStaticFunction(); // 42

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

class MyClass {}

MyClass.myStaticProperty = 42;

MyClass.myStaticProperty; // 42

最后一点:注意将静态对象与继承一起使用- 所有继承的类都共享该对象的同一副本


1

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

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

1

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

我想出了以下方法:

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

这会向所有函数添加一个“静态”方法(是的,请放轻松),在调用该方法时,会将一个空对象(_static)添加到函数对象并返回它。如果提供了init函数,则_statics将设置为init()结果。

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

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”。前缀,因此整体上更容易理解和理解。


1

摘要:

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

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
他要求的是静态变量,而不是静态函数。
康拉德·霍夫纳

1

我使用了原型,并以此方式工作:

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

Cat.COLLECTION_NAME = "cats";

或使用静态吸气剂:

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

  static get COLLECTION_NAME() {
    return "cats"
  }
}

0

在可以使用直接引用的意义上,窗口级var类似于静态变量,它们可用于应用程序的所有部分


3
对此类var的更好描述是“全局”,而不是静态的。
Patrick M

0

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

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

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

此方法有效,但是您正在污染Function.prototype
Dan

@丹:据我了解,这仅适用于圈子而非功能。至少,这是什么Chrome会的告诉我: function circle() {}| circle.prototype| circle.prototype.pi = 3.14| circle.prototype| Function.prototype| Function.__proto__(如果那是您的意思)
Aktau,2013年

0

在使用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

如果您想使用原型,那么有一种方法

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

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.