如何在 Javascript 中创建静态变量?
someFunc = () => { MyClass.myStaticVariable = 1; }
。然后只需创建一个静态方法来返回静态成员,例如 static getStatic() { return MyClass.myStaticVariable; }
。然后你可以从类外调用 MyClass.getStatic()
来获取静态数据!
btn.setAttribute( 'arr' , 0 )
我可以在脚本的任何位置获取/更改该值btn.getAttribute('arr')
如果您来自基于类的、静态类型的面向对象语言(如 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 将函数视为 first-class objects,因此作为对象,您可以将属性分配给函数。
更新: ES6 通过 class
关键字引入了 declare classes 的功能。它是现有基于原型的继承的语法糖。
static
keyword 允许您轻松定义类中的静态属性或方法。
让我们看看上面用 ES6 类实现的例子:
class MyClass { // 类构造函数,等价于 // 构造函数的函数体 constructor() { const privateVariable = 'private value'; // 构造函数作用域的私有变量 this.publicVariable = 'public value'; // 公共属性 this.privilegedMethod = function() { // 可以访问构造函数范围变量的公共方法 console.log(privateVariable); }; } // 原型方法:publicMethod() { console.log(this.publicVariable); } // 所有实例共享的静态属性 static staticProperty = 'static value';静态静态方法(){ console.log(this.staticProperty); } } // 我们可以给类原型添加属性 MyClass.prototype.additionalMethod = function() { console.log(this.publicVariable); }; var myInstance = new MyClass(); myInstance.publicMethod(); // “公共价值” myInstance.additionalMethod(); // “公共价值” myInstance.privilegedMethod(); // "私有值" MyClass.staticMethod(); // “静态值”
您可能会利用 JS 函数也是对象这一事实——这意味着它们可以具有属性。
例如,引用(现已消失的)文章 Static variables in 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);
}
如果您多次调用该函数,您会看到计数器正在递增。
这可能是比使用全局变量污染全局命名空间更好的解决方案。
这是基于闭包的另一种可能的解决方案:Trick to use static variables in 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.
这会得到相同的结果——除了这一次,返回的是增加的值,而不是显示。
countMyself.counter = countMyself.counter || initial_value;
===
进行 typeof
检查,否则你会得到一些奇怪的强制。
您可以通过 IIFE(立即调用的函数表达式)来执行此操作:
var incr = (function () {
var i = 1;
return function () {
return i++;
}
})();
incr(); // returns 1
incr(); // returns 2
var incr = (function (delta) { var i = 1; return function (delta) return i+=delta;} })();
我看过几个类似的答案,但我想提一下,this post 描述得最好,所以我想与您分享。
这是从中提取的一些代码,我已经对其进行了修改以获得一个完整的示例,希望能够为社区带来好处,因为它可以用作类的设计模板。
它也回答了你的问题:
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() 中,我们有一个 closure: 对 _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) }
});
它通过 get
和 set
函数定义属性 d.year
- 如果您不指定 set
,则该属性是只读的并且无法修改(请注意,如果您尝试,您不会收到错误设置它,但它没有效果)。每个属性都有属性 writable
、configurable
(允许在声明后更改)和 enumerable
(允许将其用作枚举器),默认为 false
。您可以通过第三个参数中的 defineProperty
设置它们,例如 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"
另请注意,在某些情况下,使用构造函数 Podcast
中的 return
语句返回自定义对象保护类内部依赖但需要公开的函数可能很有用.这将在文章系列的第 2 章(对象)中进一步解释。
您可以说 a
和 b
继承自 Podcast
。现在,如果您想在实例化 a
和 b
后向 Podcast 添加一个适用于所有这些的方法怎么办?在这种情况下,请按如下方式使用 .prototype
:
Podcast.prototype.titleAndLink = function() {
return this.title + " [" + this.link + "]";
};
现在再次调用 a
和 b
:
console.log(a.titleAndLink()); // "a [http://www.astronomycast.com]"
console.log(b.titleAndLink()); // "An Astronomy Cast [http://www.astronomycast.com]"
您可以找到有关原型的更多详细信息 here。如果你想做更多的继承,我建议研究 this。
我上面提到的article series是强烈推荐阅读的,它们还包括以下主题:
函数 对象 原型 强制执行新的构造函数 提升 自动分号插入 静态属性和方法
请注意,JavaScript 的 automatic semicolon insertion“特性”(如 6. 中所述)通常会导致代码中出现奇怪的问题。因此,我宁愿将其视为错误而不是功能。
如果您想了解更多信息,here 是一篇关于这些主题的非常有趣的 MSDN 文章,其中的一些描述提供了更多详细信息。
MDN JavaScript Guide 中的那些文章也读起来很有趣(也涵盖了上述主题):
重新介绍 JavaScript
使用对象
如果您想知道如何在 JavaScript 中模拟 c# out
参数(如在 DateTime.TryParse(str, out result)
中),您可以找到 sample code here.
那些使用 IE(没有 JavaScript 控制台,除非您使用 F12 打开开发者工具并打开控制台选项卡)可能会发现以下代码段很有用。它允许您使用上面示例中使用的 console.log(msg);
。只需在 Podcast
函数之前插入它。
为方便起见,下面是上面的代码,包含在一个完整的单个代码段中:
让控制台 = { 日志:函数(msg){ 让 canvas = document.getElementById("log"), br = canvas.innerHTML==="" ? "" : "
"; canvas.innerHTML += (br + (msg || "").toString()); }}; console.log('详见说明文'); function Podcast() { // 有了这个,你可以在没有 new 的情况下实例化(见正文中的描述) if (false === (this instanceof Podcast)) { return new Podcast(); } // 私有变量 var _somePrivateVariable = 123; // 对象属性 this.title = 'Astronomy Cast'; this.description = '基于事实的银河之旅。'; this.link = 'http://www.astronomycast.com'; this.immutableProp = function() { return _somePrivateVariable; } // 对象函数 this.toString = function() { return 'Title: ' + this.title; } }; // 静态属性 Podcast.FILE_EXTENSION = 'mp3'; // 静态函数 Podcast.download = function(podcast) { console.log('Downloading ' + podcast + ' ...'); }; // 访问静态属性/函数 Podcast.FILE_EXTENSION; // 'mp3' Podcast.download('天文演员'); // 'Downloading Astronomy cast ...' // 访问对象属性/函数 var podcast = new Podcast(); podcast.title = '辛普森一家'; console.log(podcast.toString()); // 标题:辛普森一家 console.log(podcast.immutableProp()); // 123 // getter 和 setter var d = Date.prototype; Object.defineProperty(d, "year", { get: function() { return this.getFullYear() }, set: function(y) { this.setFullYear(y) } }); // getter 和 setter - 替代语法 var obj = { a: 7, get b() { return this.a + 1; }, 设置 c(x) { this.a = x / 2 } }; // 用法:console.log(obj.a);控制台.log(obj.b); // 输出:7, 8 obj.c=40;控制台日志(obj.a);控制台.log(obj.b); // 输出:20, 21 var a=new Podcast(); var b=新播客(); a.title="a"; b.title="一个"+b.title;控制台.log(a.title); // "a" console.log(b.title); // “天文演员” Podcast.prototype.titleAndLink = function() { return this.title + " [" + this.link + "]"; }; console.log(a.titleAndLink()); // "a [http://www.astronomycast.com]" console.log(b.titleAndLink()); // “天文演员表 [http://www.astronomycast.com]”
笔记:
您可以在此处(JavaScript 最佳实践)和此处(“var”与“let”)找到有关一般 JavaScript 编程的一些好的技巧、提示和建议。还推荐这篇关于隐式类型转换(强制)的文章。
使用类并将它们编译成 JavaScript 的一种便捷方法是 TypeScript。这是一个游乐场,您可以在其中找到一些示例,向您展示它是如何工作的。即使您目前没有使用 TypeScript,也可以查看一下,因为您可以在并排视图中将 TypeScript 与 JavaScript 结果进行比较。大多数示例都很简单,但也有一个 Raytracer 示例,您可以立即试用。我建议特别查看“使用类”、“使用继承”和“使用泛型”示例,方法是在组合框中选择它们——这些是您可以立即在 JavaScript 中使用的不错的模板。 Typescript 与 Angular 一起使用。
为了在 JavaScript 中实现对局部变量、函数等的封装,我建议使用如下模式(JQuery 使用相同的技术):
当然,您可以而且应该将脚本代码放在单独的 *.js
文件中;这只是内联编写以保持示例简短。
自调用函数(也称为 IIFE = 立即调用函数表达式)是 described in more detail here。
您可以使用 arguments.callee 来存储“静态”变量(这在匿名函数中也很有用):
function () {
arguments.callee.myStaticVar = arguments.callee.myStaticVar || 1;
arguments.callee.myStaticVar++;
alert(arguments.callee.myStaticVar);
}
arguments.callee
已弃用。
callee
似乎是一件好事。我想知道他们为什么决定弃用这个黑客......:|
更新的答案:
在 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;
返回分配给它的函数,而不是您的评论所暗示的函数返回的字符串。
Foo
的 bar
属性设置为 3
,如下所示:Foo.bar = 3;
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();
以下示例和说明来自 Nicholas Zakas 的《Professional JavaScript for Web Developers 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
此示例中的 Person
构造函数可以访问私有变量名称,getName()
和 setName()
方法也是如此。使用这种模式,name 变量变为静态变量,并将在所有实例中使用。这意味着在一个实例上调用 setName()
会影响所有其他实例。调用 setName()
或创建新的 Person
实例会将 name 变量设置为新值。这会导致所有实例返回相同的值。
如果您使用的是新的 class syntax,那么您现在可以执行以下操作:
class MyClass { static get myStaticVariable() { return "一些静态变量"; } } console.log(MyClass.myStaticVariable); aMyClass = new MyClass(); console.log(aMyClass.myStaticVariable, "未定义");
这有效地在 JavaScript 中创建了一个静态变量。
MyClass
上的属性。
关于 ECMAScript 2015 引入的 class
。其他答案并不完全清楚。
以下示例展示了如何使用 ClassName
.var
合成器创建静态变量 staticVar
:
class MyClass {
constructor(val) {
this.instanceVar = val;
MyClass.staticVar = 10;
}
}
var class1 = new MyClass(1);
console.log(class1.instanceVar); // 1
console.log(class1.constructor.staticVar); // 10
// New instance of MyClass with another value
var class2 = new MyClass(3);
console.log(class1.instanceVar); // 1
console.log(class2.instanceVar); // 3
要访问静态变量,我们使用 .constructor
属性,该属性返回对创建该类的对象构造函数的引用。我们可以在两个创建的实例上调用它:
MyClass.staticVar = 11;
console.log(class1.constructor.staticVar); // 11
console.log(class2.constructor.staticVar); // 11 <-- yes it's static! :)
MyClass.staticVar = 12;
console.log(class1.constructor.staticVar); // 12
console.log(class2.constructor.staticVar); // 12
如果您想声明静态变量以在应用程序中创建常量,那么我发现以下是最简单的方法
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;
还有其他类似的答案,但没有一个对我很有吸引力。这就是我最终得到的结果:
var nextCounter = (function () {
var counter = 0;
return function() {
var temp = counter;
counter += 1;
return temp;
};
})();
除了其余部分之外,目前在 ECMA Proposals 上还有一个草稿 (stage-2 proposal),它在类中引入了 static
public 字段。 (private fields were considered)
使用提案中的示例,建议的 static
语法将如下所示:
class CustomDate {
// ...
static epoch = new CustomDate(0);
}
并且等同于其他人强调的以下内容:
class CustomDate {
// ...
}
CustomDate.epoch = new CustomDate(0);
然后您可以通过 CustomDate.epoch
访问它。
您可以在 proposal-static-class-features
中跟踪新提案。
目前,babel 通过您可以使用的 transform class properties 插件支持此功能。此外,虽然仍在进行中,但 V8
is implementing it。
有 4 种方法可以在 Javascript 中模拟函数局部静态变量。
方法一:使用函数对象属性(旧浏览器支持)
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
您可以像下面这样在 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 中最接近静态变量的是全局变量——这只是在函数或对象字面量范围之外声明的变量:
var thisIsGlobal = 1;
function foo() {
var thisIsNot = 2;
}
您可以做的另一件事是将全局变量存储在对象文字中,如下所示:
var foo = { bar : 1 }
然后像这样访问变量:foo.bar
。
如果你想创建一个全局静态变量:
var my_id = 123;
将变量替换为以下内容:
Object.defineProperty(window, 'my_id', {
get: function() {
return 123;
},
configurable : false,
enumerable : false
});
要在此处浓缩所有类概念,请对此进行测试:
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);
还有另一种方法,在浏览此线程后解决了我的要求。这完全取决于您想要使用“静态变量”实现的目标。
全局属性 sessionStorage 或 localStorage 分别允许在会话的生命周期内存储数据,或者在明确清除之前无限期地存储数据。这允许在页面/应用程序的所有窗口、框架、选项卡面板、弹出窗口等之间共享数据,并且比一个代码段中的简单“静态/全局变量”强大得多。
它避免了顶级全局变量(即 Window.myglobal)的范围、生命周期、语义、动态等方面的麻烦。不知道它的效率如何,但这对于以适中速率访问的适中数据量并不重要。
作为“sessionStorage.mydata = any”轻松访问并以类似方式检索。请参阅“JavaScript:权威指南,第六版”,David Flanagan,ISBN:978-0-596-80552-4,第 20 章,第 20.1 节。这可以通过简单的搜索轻松下载为 PDF,或者在您的 O'Reilly Safaribooks 订阅中(物超所值)。
2021 更新
在 2021 年,您可以简单地使用 static 关键字
自 2021 年 4 月起,TC39 将 STATIC
关键字移至 Stage-4 语言功能。花了很长时间才将 static
JS 功能设为官方 JS 语言功能集,等待然而,由于缺乏浏览器支持;主要浏览器现在支持 static 关键字,以及公共静态字段的开放季节和私有静态字段。
下面是实现静态 JavaScript 类成员的新方法的一般示例
class ColorFinder {
static #red = "#ff0000";
static #green = "#00ff00";
static #blue = "#0000ff";
static colorName(name) {
switch (name) {
case "red": return ColorFinder.#red;
case "blue": return ColorFinder.#blue;
case "green": return ColorFinder.#green;
default: throw new RangeError("unknown color");
}
}
// Somehow use colorName
}
上面的示例取自 TC39 存储库,静态字段
阅读更多关于这个新的 JS 语言特性的实现(点击这里)。
要阅读有关该功能本身的更多信息,以及查看演示用于静态字段的语法的示例(单击此处)。
在 JavaScript 中,变量默认是静态的。例子:
var x = 0;
function draw() {
alert(x); //
x+=1;
}
setInterval(draw, 1000);
x 的值每 1000 毫秒增加 1 它将打印 1,2,3 依此类推
函数的/类只允许其对象范围的单个构造函数。 Function Hoisting, declarations & expressions
使用 Function 构造函数创建的函数不会为其创建上下文创建闭包;它们总是在全局范围内创建。 var functionClass = function () { var currentClass = Shape; _inherits(currentClass, superClass);函数 functionClass() { superClass.call(this); // 与超类构造函数链接。 // 实例变量列表。这个.id = id;返回这个; } }(超类)
Closures - 闭包的副本具有保留数据的功能。
每个闭包的副本都被创建到具有自己的自由值或引用的函数中,每当您在另一个函数中使用函数时,都会使用闭包。 JavaScript 中的闭包就像通过 innerFunctions 维护其父函数的所有局部变量的副本。 function closureFun( args ) { // 在闭包中结束的局部变量 var num = args;数++;返回函数() { console.log(num); } } var 闭包 1 =closureFun( 5 ); var 闭包2 =closureFun(777);关闭1(); // 5 闭包2(); // 777 闭包2(); // 778 闭包1(); // 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 模式的简单糖。拥有一个方便的声明形式使类模式更易于使用,并鼓励互操作性。类支持基于原型的继承、超级调用、实例和静态方法以及构造函数。
Example:参考我之前的帖子。
您可以使用 static
关键字定义 static functions in JavaScript:
class MyClass {
static myStaticFunction() {
return 42;
}
}
MyClass.myStaticFunction(); // 42
在撰写本文时,您仍然无法在类中定义静态属性(函数除外)。静态属性仍然是 Stage 3 proposal,这意味着它们还不是 JavaScript 的一部分。但是,没有什么能阻止您像分配给任何其他对象一样简单地分配给一个类:
class MyClass {}
MyClass.myStaticProperty = 42;
MyClass.myStaticProperty; // 42
最后说明:使用带有继承的静态对象时要小心 - all inherited classes share the same copy of the object。
从某种意义上说,窗口级别的变量有点像静态变量,您可以使用直接引用,并且这些变量可用于应用程序的所有部分
与使用 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);
如果你想使用原型,那么有一种方法
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);
这样做您将能够从任何实例访问计数器变量,并且属性的任何更改都将立即反映!!
所以我在其他答案中看到的是,它们没有解决面向对象编程中静态属性的基本架构要求。
面向对象编程实际上有两种不同的风格,一种是“基于类”(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
,更改将向下级联到立即继承它的子对象。
但是,有一些“陷阱”可能会严重破坏此属性的“静态”性质,或者只是留下安全漏洞......
首先确保将构造函数隐藏在 Global 命名空间中,方法是将其封闭在另一个函数中,如 jQuery 就绪方法
$(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
});
其次也是最后一点,即使您这样做了,该属性仍然可以从您自己脚本的任何其他部分进行编辑,因此您的代码中的错误可能会覆盖其中一个子对象的属性并分离它来自父原型,因此如果您更改父属性,它将不再级联并更改子对象的静态属性。 See this jsfiddle. 在不同的场景中,我们可以 Object.freeze(obj)
停止对子对象的任何更改,或者我们可以在构造函数中设置 setter 和 getter 方法并访问闭包,这两者都有相关的复杂性。
在我看来,“静态属性”的基于类的想法和这个 Javascript 实现之间没有完美的类比。所以我认为从长远来看,使用对 Javascript 更友好的不同代码模式可能会更好。例如中央数据存储或缓存,甚至是专用的帮助对象来保存所有必要的静态变量。
我在任何答案中都没有看到这个想法,所以只需将其添加到列表中。如果它是重复的,请告诉我,我会删除它并支持另一个。
我在我的网站上创建了一种超级全球化。由于我有几个 js 文件在每次页面加载时加载,还有几十个其他 js 文件只在某些页面上加载,我将所有“全局”函数放入一个全局变量中。
在我的第一个包含的“全局”文件的顶部是声明
var cgf = {}; // Custom global functions.
然后我 delcare 几个全局辅助函数
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;
}
这当然是全局的,而不是静态的,但是因为它在每次页面加载时都会重新初始化,所以它实现了相同的目的。
在 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
对于私有静态变量,我发现是这样的:
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
_privateStatic
实际上是作为全局对象创建的(即在浏览器中使用时作为 window
的成员)。因此,虽然它是静态的,但它不是私有的,也不属于 Class
。
privilegedMethod
不等同于 OO 中的私有方法,因为它似乎可以在 MyClass 的实例上调用?你的意思是它有特权,因为它可以访问privateVariable
?this.constructor
从“实例方法”访问静态变量吗?如果是,则值得将其添加到答案中。MyClass.prototype.staticProperty = "baz";
,或者更正确地理解 OO 原则,静态属性实际上应该定义为匿名函数MyClass.prototype.staticProperty = function () {return staticVar;}
,这样所有实例都可以访问单个变量,该变量也可以使用 setter 进行更改。