Difference between variable declaration syntaxes in Javascript (including global variables)?
声明变量之间是否有任何区别:
1 | var a=0; //1 |
……这样:
1 | a=0; //2 |
…或:
1 | window.a=0; //3 |
在全球范围内?
是的,有一些不同,但在实际情况下,它们通常不是很大的。好的。
还有第四条路,到ES2015(ES6)还有两条。我在结尾处添加了第四种方法,但在1之后插入了ES2015方法(您将看到原因),因此我们有:好的。
1 2 3 4 5 6 | var a = 0; // 1 let a = 0; // 1.1 (new with ES2015) const a = 0; // 1.2 (new with ES2015) a = 0; // 2 window.a = 0; // 3 this.a = 0; // 4 |
那些声明解释了
#1台
这就创建了一个全局变量,它也是全局对象的一个属性,我们在浏览器上(或通过一个全局范围,非严格代码)以
在规范术语中,它在全局环境的对象环境记录上创建一个标识符绑定。这使其成为全局对象的属性,因为全局对象是保存全局环境的对象环境记录的标识符绑定的位置。这就是属性不可删除的原因:它不仅是一个简单的属性,而且是一个标识符绑定。好的。
绑定(变量)是在第一行代码运行之前定义的(请参见下面的"当
请注意,在IE8及更早版本中,
#1.1
这将创建一个不是全局对象属性的全局变量。从ES2015年开始,这是一件新鲜事。好的。
在规范术语中,它在全局环境的声明性环境记录(而不是对象环境记录)上创建标识符绑定。全球环境的独特之处在于有一个分割的环境记录,一个记录了全球对象(对象环境记录)上的所有旧内容,另一个记录了所有新内容(
绑定是在执行其封闭块中的任何逐步代码之前创建的(在本例中,是在运行任何全局代码之前),但在逐步执行到达
#1.2
创建全局常量,该常量不是全局对象的属性。好的。
#2台
这将在全局对象上隐式创建属性。因为它是一个普通属性,所以可以删除它。我建议不要这样做,以后任何人读你的代码都不清楚。如果使用ES5的严格模式,则执行此操作(分配给不存在的变量)是一个错误。这是使用严格模式的几个原因之一。好的。
有趣的是,在IE8和更早的版本中,创建的属性不可枚举(不会出现在
#3台
这会显式地在全局对象上创建一个属性,使用引用全局对象的
此属性在IE8和早期版本以及我尝试过的其他所有浏览器上都是可枚举的。好的。
#4台
与3完全相同,只是我们通过
我所说的"删除"或"删除"是什么意思?正是这样:通过
1 2 3 4 | window.a = 0; display("'a' in window?" + ('a' in window)); // displays"true" delete window.a; display("'a' in window?" + ('a' in window)); // displays"false" |
警告:IE8(可能更早,IE9-IE11处于中断的"兼容性"模式):它不会让您删除
1 2 3 4 5 6 | try { delete window.prop; } catch (e) { window.prop = undefined; } |
这将尝试删除该属性,如果抛出异常,它将执行下一个最佳操作,并将该属性设置为
这仅适用于
通过
这可能会让人困惑,所以让我们看看:好的。
1 2 3 4 5 6 7 8 9 10 | display("foo in window?" + ('foo' in window)); // displays"true" display("window.foo =" + window.foo); // displays"undefined" display("bar in window?" + ('bar' in window)); // displays"false" display("window.bar =" + window.bar); // displays"undefined" var foo ="f"; bar ="b"; display("foo in window?" + ('foo' in window)); // displays"true" display("window.foo =" + window.foo); // displays"f" display("bar in window?" + ('bar' in window)); // displays"true" display("window.bar =" + window.bar); // displays"b" |
活生生的例子:好的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | display("foo in window?" + ('foo' in window)); // displays"true" display("window.foo =" + window.foo); // displays"undefined" display("bar in window?" + ('bar' in window)); // displays"false" display("window.bar =" + window.bar); // displays"undefined" var foo ="f"; bar ="b"; display("foo in window?" + ('foo' in window)); // displays"true" display("window.foo =" + window.foo); // displays"f" display("bar in window?" + ('bar' in window)); // displays"true" display("window.bar =" + window.bar); // displays"b" function display(msg) { var p = document.createElement('p'); p.innerHTML = msg; document.body.appendChild(p); } |
好的。
如您所见,符号
因此,当这运行时:好的。
1 2 3 | display(a); // undefined var a = 0; display(a); // 0 |
这将引发一个错误:好的。
1 2 3 | display(a); // ReferenceError: a is not defined let a = 0; display(a); |
在相同的上下文中重复
下面是一个例子,说明
1 2 3 4 5 6 7 8 | var a = 0; console.log(a); if (true) { console.log(a); // ReferenceError: a is not defined let a = 1; console.log(a); } |
注意,第二个
1 2 3 4 5 6 7 | (function() { var a = 0; // `a` is NOT a property of `window` now function foo() { alert(a); // Alerts"0", because `foo` can access `a` } })(); |
在这个例子中,我们定义了一个函数并立即执行它(末尾是
以这种方式使用的函数通常称为作用域函数。作用域函数中定义的函数可以访问作用域函数中定义的变量,因为它们是该数据的闭包(请参见:闭包在我的贫血小博客上并不复杂)。好的。好啊。
保持简单:
1 | a = 0 |
上面的代码给出了一个全局范围变量
1 | var a = 0; |
此代码将给出一个在当前作用域中使用的变量,并在该变量下
1 | window.a = 0; |
这通常与全局变量相同。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | Index.html var varDeclaration = true; noVarDeclaration = true; window.hungOnWindow = true; document.hungOnDocument = true; <script src="external.js"> /* external.js */ console.info(varDeclaration == true); // could be .log, alert etc // returns false in IE8 console.info(noVarDeclaration == true); // could be .log, alert etc // returns false in IE8 console.info(window.hungOnWindow == true); // could be .log, alert etc // returns true in IE8 console.info(document.hungOnDocument == true); // could be .log, alert etc // returns ??? in IE8 (untested!) *I personally find this more clugy than hanging off window obj |
是否存在默认情况下挂起所有变量的全局对象?例如:"globals.novar声明"
基于T.J.克劳德的出色回答:(主题外:避免把
这是他的想法的一个例子:
HTML
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <!DOCTYPE html> <html> <head> <script type="text/javascript" src="init.js"> <script type="text/javascript"> MYLIBRARY.init(["firstValue", 2,"thirdValue"]); <script src="script.js"> </head> <body> Hello ! </body> </html> |
init.js(基于此答案)
1 2 3 4 5 6 7 8 9 10 11 12 13 | var MYLIBRARY = MYLIBRARY || (function(){ var _args = {}; // private return { init : function(Args) { _args = Args; // some other initialising }, helloWorld : function(i) { return _args[i]; } }; }()); |
JScript
1 2 3 4 | // Here you can use the values defined in the html as if it were a global variable var a ="Hello World" + MYLIBRARY.helloWorld(2); alert(a); |
这是PLNKR。希望有帮助!
在全局范围内没有语义差异。
但是您确实应该避免使用
也可以使用闭包来避免编辑全局范围
1 2 3 4 5 6 | (function() { // do stuff locally // Hoist something to global scope window.someGlobal = someLocal }()); |
在绝对必要时,始终使用闭包并提升到全局范围。无论如何,您应该在大多数通信中使用异步事件处理。
正如@avianmoncellor所提到的,
所以还是坚持用