如何在Javascript中创建静态变量?
当前回答
更新答案:
在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中,函数是对象。
其他回答
以下示例和解释来自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()方法也是如此。使用此模式,name变量将变为静态,并将在所有实例中使用。这意味着在一个实例上调用setName()会影响所有其他实例。调用setName()或创建新的Person实例会将name变量设置为新值。这会导致所有实例返回相同的值。
摘要:
在ES6/ES 2015中,class关键字与附带的静态关键字一起引入。请记住,这是javavscript所体现的原型继承模型的语法糖。static关键字对方法的工作方式如下:
类狗{静态树皮(){console.log('wof');}//类是隐藏的函数对象//树皮方法位于Dog函数对象上makeSound(){console.log('bark');}//makeSound位于Dog.prototype对象上}//要创建静态变量,只需在类的原型上创建一个属性Dog.prototype.breed=“Pitbull”;//因此,要定义静态属性,我们不需要“static”关键字。const蓬松=新狗();const vicky=新狗();控制台.日志(绒毛.品种,vicky.品种);//更改静态变量会更改所有对象上的静态变量Dog.prototype.breed=“梗”;控制台.日志(绒毛.品种,vicky.品种);
我已经看到了一些类似的答案,但我想提到这篇文章描述得最好,所以我想和大家分享一下。
下面是从中提取的一些代码,我已经对其进行了修改,以获得一个完整的示例,这有望为社区带来好处,因为它可以用作类的设计模板。
它还回答了您的问题:
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) }
});
它通过get和set函数定义属性d.year-如果未指定set,则该属性是只读的,无法修改(请注意,如果尝试设置该属性,则不会出现错误,但没有任何效果)。每个属性都具有可写、可配置(允许在声明后更改)和可枚举(允许将其用作枚举器)的属性,这些属性默认为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
笔记:
为了避免在忘记新关键字时出现意外行为,我建议您在函数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]"
您可以在这里找到有关原型的更多详细信息。如果你想做更多的继承,我建议你研究一下。
强烈建议阅读我上面提到的系列文章,其中还包括以下主题:
功能物体原型对构造函数强制执行新吊起自动插入分号静态财产和方法
请注意,JavaScript的自动分号插入“特性”(如6.中所述)通常会导致代码中出现奇怪的问题。因此,我宁愿将其视为一个bug而不是一个特性。
如果您想阅读更多,这里有一篇关于这些主题的MSDN文章,其中一些描述提供了更多细节。
阅读MDN JavaScript指南中的文章也很有趣(也涵盖了上述主题):
JavaScript简介使用对象
如果您想知道如何在JavaScript中模拟c#out参数(如DateTime.TryParse(str,out result)),可以在这里找到示例代码。
使用IE的人(除非使用F12打开开发人员工具并打开控制台选项卡,否则IE没有JavaScript控制台)可能会发现以下代码片段很有用。它允许您使用console.log(msg);如在上述示例中所使用的。只需将其插入播客功能之前。
为了方便起见,下面是上面一个完整的代码片段中的代码:
让控制台={log:function(msg){let canvas=document.getElementById(“log”),br=canvas.innerHTML==“”?“”:“<br/>”;canvas.innerHTML+=(br+(msg||“”).toString());}};console.log('有关详细信息,请参阅解释文本');函数播客(){//使用此选项,您可以在没有新建的情况下进行实例化(请参阅文本中的描述)if(false==(播客的这个实例)){return new播客();}//私有变量var_somePrivateVariable=123;//对象财产this.title='天文学演员';this.description='基于事实的银河之旅';this.link='http://www.astronomycast.com';this.immutableProp=函数(){return _somePrivateVariable;}//目标函数this.toString=函数(){return'标题:'+this.Title;}};//静态特性播客.FILE_EXTENSION=“mp3”;//静态函数Podcast.download=函数(播客){console.log(“下载”+播客+“…”);};//访问静态财产/函数播客.FILE_EXTENSION;//'mp3'播客.下载('天文学广播');//'正在下载天文学演员…'//访问对象财产/函数var podcast=新播客();podcast.title=“辛普森一家”;console.log(podcast.toString());//标题:《辛普森一家》console.log(podco.immutableProp());//123//吸气器和settervar d=日期.协议类型;Object.defineProperty(d,“年”{获取:函数(){return this.getFullYear()},集合:函数(y){this.setFullYear(y)}});//getters和setters-替代语法变量obj={a: 7中,获取b(){返回此.a+1;},集合c(x){这个.a=x/2}};//用法:控制台日志(obj.a);console.log(obj.b);//输出:7,8物镜c=40;控制台日志(obj.a);console.log(obj.b);//输出:20,21var a=新播客();var b=新播客();a.title=“a”;b.title=“An”+b.title;console.log(a.title);//“a”console.log(b.title);//“天文学演员”Podcast.prototype.titleAndLink=函数(){return this.title+“[”+this.link+“]”;};console.log(a.titleAndLink());//“一个[http://www.astronomycast.com]"console.log(b.titleAndLink());//“天文学演员[http://www.astronomycast.com]"<div id=“log”></div>
笔记:
在这里(JavaScript最佳实践)和那里(“var”与“let”)都可以找到关于JavaScript编程的一些好的提示、提示和建议。还推荐这篇关于隐式类型转换(强制)的文章。使用类并将其编译为JavaScript的一种方便方法是TypeScript。这里是一个游乐场,你可以在那里找到一些例子,告诉你它是如何工作的。即使您目前没有使用TypeScript,也可以查看一下,因为您可以在并排视图中将TypeScript与JavaScript结果进行比较。大多数示例都很简单,但也有一个光线跟踪器示例,您可以立即尝试。我建议特别关注“使用类”、“使用继承”和“使用泛型”示例,方法是在组合框中选择它们-这些都是很好的模板,可以立即在JavaScript中使用。字体与Angular一起使用。为了在JavaScript中实现本地变量、函数等的封装,我建议使用如下模式(JQuery使用相同的技术):
<html><head></head><body><脚本>“使用严格”;//模块模式(自调用函数)const myModule=(函数(上下文){//要允许替换函数,请使用“var”,否则保留“const”//将变量和函数与本地模块范围放在此处:var print=函数(str){if(str!==undefined)context.document.write(str);context.document.write(“<br/><br/>”);回来}// ... 更多变量。。。//主要方法var _main=函数(标题){if(title!==未定义)打印(title);打印(“<b>上次修改时间:</b>”+context.document.lastModified+“<br/>”);// ... 更多代码。。。}//公共方法返回{主:_Main// ... 更多公共方法、财产。。。};})(本);//使用模块myModule.Main(“<b>模块演示</b>”);</script></body></html>
当然,您可以也应该将脚本代码放在一个单独的*.js文件中;这只是为了保持示例简短而内联编写的。
这里更详细地描述了自调用函数(也称为IIFE=立即调用函数表达式)。
我使用了原型,并以这种方式工作:
class Cat {
constructor() {
console.log(Cat.COLLECTION_NAME);
}
}
Cat.COLLECTION_NAME = "cats";
或使用静态吸气剂:
class Cat {
constructor() {
console.log(Cat.COLLECTION_NAME);
}
static get COLLECTION_NAME() {
return "cats"
}
}
如果您想在应用程序中声明用于创建常量的静态变量,那么我发现以下是最简单的方法
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;