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


当前回答

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

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

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

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

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

其他回答

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

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

这使用。。。args比较慢,有没有办法第一次使用父函数的作用域而不是传递所有参数?


我的用例:

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

如果要在作用域之外使用child_process,可以将其分配给copyToCclipboard的属性

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

我已经看到了一些类似的答案,但我想提到这篇文章描述得最好,所以我想和大家分享一下。

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

它还回答了您的问题:

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=立即调用函数表达式)。

在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

除其他内容外,目前还有一个关于ECMA提案的草案(第2阶段提案),它在类中引入了静态公共字段。(考虑了私人领域)

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

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

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

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

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

您可以在提案静态类特性中跟踪新提案。


目前,babel通过您可以使用的转换类财产插件支持此功能。此外,尽管仍在进行中,V8正在实现它。

摘要:

在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.品种);