Static variables in JavaScript
如何在javascript中创建静态变量?
如果您来自一个基于类的静态类型的面向对象语言(如Java、C++或C语言),那么我假设您正在尝试创建一个与"类型"相关联的变量或方法,而不是与实例相关联的变量或方法。
使用带有构造函数函数的"经典"方法的示例可能有助于您了解基本OO javascript的概念:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | 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(); |
您可以利用JS函数也是对象这一事实——这意味着它们可以有属性。
例如,引用javascript中(现已消失)文章静态变量的示例:
1 2 3 4 5 6 7 8 9 10 | 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中使用静态变量的技巧:
1 2 3 4 5 6 7 | 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. |
这会得到相同的结果——除了这次返回的是递增的值,而不是显示的值。
通过IIFE(立即调用的函数表达式)执行此操作:
1 2 3 4 5 6 7 8 9 10 | var incr = (function () { var i = 1; return function () { return i++; } })(); incr(); // returns 1 incr(); // returns 2 |
您可以使用arguments.callee存储"static"变量(这在匿名函数中也很有用):
1 2 3 4 5 | function () { arguments.callee.myStaticVar = arguments.callee.myStaticVar || 1; arguments.callee.myStaticVar++; alert(arguments.callee.myStaticVar); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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(); |
我看到了一些类似的答案,但我想说的是,这篇文章描述的最好,所以我想和大家分享一下。好的。
这里有一些从中提取的代码,我已经修改了这些代码,以得到一个完整的示例,希望能给社区带来好处,因为它可以用作类的设计模板。好的。
它还回答了您的问题:好的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | 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 + ' ...'); }; |
在该示例中,可以按如下方式访问静态属性/函数:好的。
1 2 3 | // access static properties/functions Podcast.FILE_EXTENSION; // 'mp3' Podcast.download('Astronomy cast'); // 'Downloading Astronomy cast ...' |
对象属性/功能简单如下:好的。
1 2 3 4 5 | // 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。看看这个代码片段(其中
1 2 3 4 5 6 | // getters and setters var d = Date.prototype; Object.defineProperty(d,"year", { get: function() {return this.getFullYear() }, set: function(y) { this.setFullYear(y) } }); |
它通过
此语法也有效:好的。
1 2 3 4 5 | // getters and setters - alternative syntax var obj = { a: 7, get b() {return this.a + 1;}, set c(x) {this.a = x / 2} }; |
它定义了一个可读/可写属性
用途:好的。
1 2 3 | 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 |
笔记:好的。
为了避免在您忘记
1 2 3 4 5 6 7 | // instantiation helper function Podcast() { if(false === (this instanceof Podcast)) { return new Podcast(); } // [... same as above ...] }; |
现在,以下两个实例都将按预期工作:好的。
1 2 | var podcast = new Podcast(); // normal usage, still allowed var podcast = Podcast(); // you can omit the new keyword because of the helper |
"new"语句创建一个新对象并复制所有属性和方法,即好的。
1 2 3 4 5 | 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" |
还要注意,在某些情况下,使用构造函数函数
可以说,
1 2 3 | Podcast.prototype.titleAndLink = function() { return this.title +" [" + this.link +"]"; }; |
现在再给
1 2 | console.log(a.titleAndLink()); //"a [http://www.astronomycast.com]" console.log(b.titleAndLink()); //"An Astronomy Cast [http://www.astronomycast.com]" |
你可以在这里找到更多关于原型的细节。如果你想做更多的继承,我建议你研究一下。好的。
我上面提到的系列文章非常推荐阅读,它们还包括以下主题:好的。
请注意,javascript的自动分号插入"特性"(如6中所述)常常导致代码中出现奇怪的问题。因此,我宁愿把它看作一个bug,而不是一个特性。好的。
如果您想了解更多,这里有一篇关于这些主题的非常有趣的msdn文章,其中的一些描述提供了更多的细节。好的。
还有什么值得阅读的(也包括上面提到的主题)是MDN JavaScript指南中的文章:好的。
- 重新介绍javascript
- 使用对象
如果您想知道如何在javascript中模拟c
那些使用IE的人(除非您使用F12打开开发人员工具并打开控制台选项卡,否则没有用于JavaScript的控制台)可能会发现以下代码段很有用。它允许您使用上述示例中使用的
为了您的方便,下面的代码是完整的单个代码片段:好的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 | 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]" |
1 |
好的。
笔记:好的。
关于javascript编程的一些好提示、提示和建议,您可以在这里(javascript最佳实践)和那里找到("var"与"let")。本文还建议使用隐式类型转换(强制)。好的。
使用类并将其编译为JavaScript的一种方便方法是typescript。这里是一个游乐场,你可以在这里找到一些例子,向你展示它是如何工作的。即使您现在不使用typescript,您也可以查看,因为您可以将typescript与并排视图中的javascript结果进行比较。大多数例子都很简单,但也有一个光线跟踪器示例,您可以立即试用。我特别建议通过在组合框中选择"使用类"、"使用继承"和"使用泛型"示例来研究它们——这些是可以立即在JavaScript中使用的很好的模板。打字稿与斜角字一起使用。好的。
为了在javascript中实现局部变量、函数等的封装,我建议使用如下的模式(jquery使用相同的技术):好的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | <html> <head></head> <body> '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("last modified: " + context.document.lastModified +"<br/>"); // ... more code ... } // public methods return { Main: _main // ... more public methods, properties ... }; })(this); // use module myModule.Main("Module demo"); </body> </html> |
好的。
当然,您可以并且应该将脚本代码放在一个单独的
更新答案:
在ecmascript 6中,可以使用
1 2 3 4 5 6 7 8 9 10 11 12 | 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中可以这样做:
1 2 3 4 5 6 7 8 9 10 11 | //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 |
您可以分配给
下面的例子和解释来自NicholasZakas的《面向Web开发人员的专业JavaScript第二版》。这是我正在寻找的答案,所以我认为在这里添加它会有所帮助。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | (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 |
本例中的
如果使用新的类语法,那么现在可以执行以下操作:
1 2 3 4 5 6 7 8 9 10 | class MyClass { static get myStaticVariable() { return"some static variable"; } } console.log(MyClass.myStaticVariable); aMyClass = new MyClass(); console.log(aMyClass.myStaticVariable,"is undefined"); |
这在javascript中有效地创建了一个静态变量。
如果要声明静态变量以在应用程序中创建常量,那么我发现下面是最简单的方法
1 2 3 4 5 6 7 8 9 10 11 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; |
关于ECMAScript 2015引入的
下面是一个示例,演示如何使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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 |
为了访问静态变量,我们使用
1 2 3 4 5 6 7 | 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 |
您可以在下面这样的javascript中创建一个静态变量。这里,
1 2 3 4 5 6 7 8 9 10 11 | 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 |
可以使用
1 2 3 4 5 6 7 | // 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 |
还有其他类似的答案,但没有一个能吸引我。我的结论是:
1 2 3 4 5 6 7 8 | var nextCounter = (function () { var counter = 0; return function() { var temp = counter; counter += 1; return temp; }; })(); |
在javascript中,默认情况下变量是静态的。例子:
1 2 3 4 5 6 7 8 | var x = 0; function draw() { alert(x); // x+=1; } setInterval(draw, 1000); |
x的值每1000毫秒递增1它将打印1、2、3等等
如果要生成全局静态变量:
1 | var my_id = 123; |
将变量替换为以下内容:
1 2 3 4 5 6 7 | Object.defineProperty(window, 'my_id', { get: function() { return 123; }, configurable : false, enumerable : false }); |
javascript中最接近静态变量的是全局变量-这只是一个在函数或对象文本范围之外声明的变量:
1 2 3 4 5 | var thisIsGlobal = 1; function foo() { var thisIsNot = 2; } |
您可以做的另一件事是将全局变量存储在这样的对象文本中:
1 | var foo = { bar : 1 } |
然后像这样访问变量标签:
还有另一种方法,在浏览完这个线程后解决了我的需求。这完全取决于您想要用"静态变量"实现什么。
全局属性sessionstorage或localstorage允许在会话的生命周期内或无限长的时间内存储数据,直到明确清除为止。这允许在页面/应用程序的所有窗口、框架、选项卡面板、弹出窗口等之间共享数据,并且比一个代码段中的简单"静态/全局变量"功能强大得多。
它避免了顶级全局变量(即window.myglobal)的作用域、生存期、语义、动态等的所有麻烦。不知道它有多高效,但对于以适度的速率访问的少量数据来说,这并不重要。
以"sessionstorage.mydata=anything"轻松访问,检索方式类似。见"javascript:最终指南,第六版",David Flanagan,ISBN:978-0-596-80552-4,第20章,第20.1节。这很容易通过简单的搜索以PDF格式下载,或者在您的O'Reilly SafariBooks订阅中下载(它的重量相当于黄金)。
要在此处浓缩所有类概念,请测试:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | 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是如何翻译这些概念的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | #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); |
除其他外,目前还有一份关于ECMA提案的草案(第二阶段提案),该草案在课堂上介绍了
使用建议中的示例,建议的
1 2 3 4 | class CustomDate { // ... static epoch = new CustomDate(0); } |
并等同于其他人强调的以下内容:
1 2 3 4 | class CustomDate { // ... } CustomDate.epoch = new CustomDate(0); |
然后您可以通过
你可以在
目前,babel支持这个带有转换类属性插件的特性,您可以使用它。此外,尽管仍在进行中,
函数的/类只允许对其对象范围使用单个构造函数。
Functions created with the Function constructor do not create closures to their creation contexts; they always are created in the global scope.
1
2
3
4
5
6
7
8 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)
闭包-闭包的副本具有保留数据的功能。
- Each closure's copies are created to a function with their own free values or references, Whenever you use function inside another function, a closure is used.
A closure in JavaScript is like maintaining a copy of all the local variables of its parent function by the innerFunctions.
1
2
3
4
5
6
7
8
9
10
11
12 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)
The Object.defineProperty() method defines a new property directly on an object, or modifies an existing property on an object, and returns the object.
通过使用``创建了一些方法,以便每个人都能轻松理解函数类。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 | '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; } |
下面的代码片段是关于每个实例都有自己的实例成员副本和公共静态成员的测试。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | 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 |
Static method calls are made directly on the class and are not callable on instances of the class. But you can achieve the calls for static members from inside an instance.
Using syntax:
1 this.constructor.staticfunctionName();
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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模式简单。拥有一个简单的声明形式使类模式更容易使用,并鼓励互操作性。类支持基于原型的继承、超级调用、实例和静态方法以及构造函数。
例句:参考我以前的文章。
在javascript中有4种方法可以模拟函数局部静态变量。
方法1:使用函数对象属性(旧浏览器支持)
1 2 3 4 5 6 7 8 9 | function someFunc1(){ if( !('staticVar' in someFunc1) ) someFunc1.staticVar = 0 ; alert(++someFunc1.staticVar) ; } someFunc1() ; //prints 1 someFunc1() ; //prints 2 someFunc1() ; //prints 3 |
方法2:使用闭包,变量1(在旧浏览器中支持)
1 2 3 4 5 6 7 8 9 10 | var someFunc2 = (function(){ var staticVar = 0 ; return function(){ alert(++staticVar) ; } })() someFunc2() ; //prints 1 someFunc2() ; //prints 2 someFunc2() ; //prints 3 |
方法3:使用闭包,变量2(在旧浏览器中也支持)
1 2 3 4 5 6 7 8 9 | var someFunc3 ; with({staticVar:0}) var someFunc3 = function(){ alert(++staticVar) ; } someFunc3() ; //prints 1 someFunc3() ; //prints 2 someFunc3() ; //prints 3 |
方法4:使用闭包,变体3(需要ECMAScript 2015支持)
1 2 3 4 5 6 7 8 9 10 | { let staticVar = 0 ; function someFunc4(){ alert(++staticVar) ; } } someFunc4() ; //prints 1 someFunc4() ; //prints 2 someFunc4() ; //prints 3 |
总结:
在
1 2 3 4 5 6 7 8 9 10 | 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 } |
在chrome devtools中,我们可以很好地将其可视化:
现在我们已经创建了一个
在JavaScript中,没有术语或关键字static,但是我们可以将这些数据直接放入函数对象(就像在任何其他对象中一样)。
1 2 3 4 5 6 7 8 | 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 |
在javascript中没有静态变量。这种语言是基于原型的面向对象的,所以没有类,而是从原型中对象"复制"自己。
您可以使用全局变量或原型(向原型添加属性)来模拟它们:
1 2 3 | function circle(){ } circle.prototype.pi=3.14159 |
窗口级变量在某种意义上类似于静态变量,您可以使用直接引用,这些变量可用于应用程序的所有部分。
使用使用jquery的MVC网站,我希望确保某些事件处理程序中的Ajax操作只能在上一个请求完成后执行。我使用"static"jqxhr对象变量来实现这一点。
给定以下按钮:
1 | <button type="button" onclick="ajaxAction(this, { url: '/SomeController/SomeAction' })">Action!</button> |
对于我的点击处理程序,我通常使用这样的iLife:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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); |
如果您想使用原型,那么有一种方法
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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); |
这样,您将能够从任何实例访问计数器变量,并且属性中的任何更改都将立即反映出来!!
我通常使用这种方法有两个主要原因:
如果我想存储函数的局部值,我会使用"local.x"、"local.y"、"local.tempdata"等函数…
如果我想存储函数静态值,我会使用"static.o"、"static.info"、"static.count"等函数…
[update2]:同样的方法,但使用的是iife方法!
[update1]:"static"和"local"函数对象是通过预编辑脚本自动创建的!
所以我看到的其他答案是,它们没有解决面向对象编程中静态属性的基本体系结构需求。
面向对象的编程实际上有两种不同的风格,一种是"基于类的"(C++、C语言、Java等),另一种是"原型"(JavaScript)。在基于类的语言中,"静态属性"应该与类关联,而不是与实例化的对象关联。这个概念实际上在类似于javascript的原型语言中更直观地工作,因为您只是像这样将属性指定为父原型的值。
1 2 | function MyObject() {}; MyObject.prototype.staticAttribute ="some value"; |
从这个构造函数中实例化的每个对象访问它,就像这样…
1 2 3 4 | 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 |
现在,如果继续更改
但是,有一些"gotchas"可能会严重破坏该属性的"静态"性质,或者只留下安全漏洞…
首先,确保通过将构造函数封闭在另一个函数(如jquery ready方法)中来隐藏全局命名空间中的构造函数。
1 2 3 4 5 6 7 8 | $(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 }); |
第二个也是最后一个,即使这样做,属性仍然可以从自己脚本的任何其他部分进行编辑,因此可能是代码中的bug将属性写入其中一个子对象,并将其与父原型分离,因此如果更改父属性,它将不再层叠和更改stati。子对象的C属性。看看这个J小提琴。在不同的场景中,我们可以使用
在我看来,在基于类的"静态属性"概念和这个JavaScript实现之间并没有完美的相似之处。因此,我认为从长远来看,使用一种更适合JavaScript的不同代码模式可能会更好。例如一个中央数据存储或缓存,甚至一个专用的助手对象来保存所有必要的静态变量。
我没有在任何答案中看到这个想法,所以只是把它添加到列表中。如果是复制品,请告诉我,我会删除它并对另一个进行升级投票。
我在自己的网站上创建了一种超级全球化。因为我有几个JS文件在每次页面加载时都会被加载,还有几十个其他JS文件只在某些页面上加载,所以我将所有"global"函数放在一个全局变量中。
在我第一个包含的"全局"文件的顶部是声明
1 | var cgf = {}; // Custom global functions. |
然后我将介绍几个全局助手函数
1 2 3 4 | cgf.formBehaviors = function() { // My form behaviors that get attached in every page load. } |
然后,如果我需要一个静态变量,我只需要将它存储在范围之外,比如文档就绪或行为附件之外。(我使用jquery,但它应该在javascript中工作)
1 2 3 4 5 6 7 8 9 10 | 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 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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 |
试试这个:
如果我们定义一个属性并重写它的getter和setter以使用函数对象属性,那么理论上,在javascript中可以有一个静态变量。
例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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. |
在JavaScript中,所有内容要么是基元类型,要么是对象。函数是对象&mdash;(键值对)。
创建函数时,将创建两个对象。一个对象表示函数本身,另一个对象表示函数的原型。
从这个意义上说,函数是一个具有以下属性的对象:
1 2 3 | function name, arguments length and the functional prototype. |
那么在哪里设置静态属性:两个位置,要么在函数对象内部,要么在函数原型对象内部。
下面是一个片段,它使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | 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); |
其主要思想是实例
我经常使用静态函数变量,但遗憾的是JS没有内置的机制。我经常看到代码,其中变量和函数是在外部范围中定义的,即使它们只是在一个函数中使用。这很难看,容易出错,只是在自找麻烦…
我想出了以下方法:
1 2 3 4 5 6 | 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。
然后你可以做:
1 2 3 4 5 | function f() { const _s = f.statics(() => ({ v1=3, v2=somefunc() }); if (_s.v1==3) { ++_s.v1; _s.v2(_s.v1); } } |
与另一个正确答案的IIFE相比,这有一个缺点,即在每个函数调用上添加一个赋值和一个if,并向函数添加一个"statics"成员,但是有几个优点:参数在顶部,而不是在内部函数中,使用内部函数代码中的"static"进行解释。ICIT的前缀是"_s.",而且查看和理解起来更简单。
"班级"制度
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | var Rect = (function(){ 'use strict'; return { instance: function(spec){ 'use strict'; spec = spec || {}; /* Private attributes and methods */ var x = (spec.x === undefined) ? 0 : spec.x, y = (spec.x === undefined) ? 0 : spec.x, width = (spec.width === undefined) ? 1 : spec.width, height = (spec.height === undefined) ? 1 : spec.height; /* Public attributes and methods */ var that = { isSolid: (spec.solid === undefined) ? false : spec.solid }; that.getX = function(){ return x; }; that.setX = function(value) { x = value; }; that.getY = function(){ return y; }; that.setY = function(value) { y = value; }; that.getWidth = function(){ return width; }; that.setWidth = function(value) { width = value; }; that.getHeight = function(){ return height; }; that.setHeight = function(value) { height = value; }; return that; }, copy: function(obj){ return Rect.instance({ x: obj.getX(), y: obj.getY(), width: obj.getWidth, height: obj.getHeight(), solid: obj.isSolid }); } } })(); |
你可以这样想。在
并将其设置为
当然,您可以使用jquery管理前一个标记中的文本。实际上,这个标签成为静态变量。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | { 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()); |
这只是我在某个地方学到的静态变量的另一种方法。
当我看到这个的时候,我记得javascript的闭包。我是这样做的……
1 2 3 4 5 6 7 8 9 10 11 | 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 |