本文翻译自:Difference between variable declaration syntaxes in Javascript (including global variables)?
Is there any difference between declaring a variable: 声明变量之间有什么区别:
var a=0; //1
...this way: ...这条路:
a=0; //2
...or: ...要么:
window.a=0; //3
in global scope? 在全球范围内?
参考:https://stackoom.com/question/koSt/Javascript中的变量声明语法-包括全局变量-之间的区别
Index.html
/* 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
Is there a global object that all vars are hung off of by default? 是否有一个全局对象,默认情况下所有变量都挂起? eg: 'globals.noVar declaration' 例如:“ globals.noVar声明”
Bassed on the excellent answer of TJ Crowder : ( Off-topic: Avoid cluttering window
) 惊叹于TJ Crowder的出色回答:( 题外话:避免window
混乱 )
This is an example of his idea: 这是他的想法的一个例子:
Html HTML
Hello !
init.js (Based on this answer ) init.js (基于此答案 )
var MYLIBRARY = MYLIBRARY || (function(){
var _args = {}; // private
return {
init : function(Args) {
_args = Args;
// some other initialising
},
helloWorld : function(i) {
return _args[i];
}
};
}());
script.js script.js
// 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);
Here's the plnkr . 这是plnkr 。 Hope it help ! 希望对您有所帮助!
In global scope there is no semantic difference. 在全局范围内,没有语义差异。
But you really should avoid a=0
since your setting a value to an undeclared variable. 但是您确实应该避免a=0
因为您将值设置为未声明的变量。
Also use closures to avoid editing global scope at all 还使用闭包来避免完全编辑全局范围
(function() {
// do stuff locally
// Hoist something to global scope
window.someGlobal = someLocal
}());
Always use closures and always hoist to global scope when its absolutely neccesary. 绝对必要时,请始终使用闭包,并始终将其提升到全局范围。 You should be using asynchronous event handling for most of your communication anyway. 无论如何,您应该在大多数通信中使用异步事件处理。
As @AvianMoncellor mentioned there is an IE bug with var a = foo
only declaring a global for file scope. 正如@AvianMoncellor提到的那样,有一个IE错误,其中var a = foo
仅声明了文件范围的全局值。 This is an issue with IE's notorious broken interpreter. 这是IE臭名昭著的解释器的问题。 This bug does sound familiar so it's probably true. 这个错误听起来确实很熟悉,所以可能是事实。
So stick to window.globalName = someLocalpointer
所以坚持window.globalName = someLocalpointer
Yes, there are a couple of differences, though in practical terms they're not usually big ones. 是的,有一些差异,尽管实际上它们通常并不大。
There's a fourth way, and as of ES2015 (ES6) there's two more. 还有第四种方法,从ES2015(ES6)开始,还有另外两种方法。 I've added the fourth way at the end, but inserted the ES2015 ways after #1 (you'll see why), so we have: 我在末尾添加了第四种方式,但是在#1之后插入了ES2015方式(您会看到原因),因此我们有:
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 var a = 0;
#1 var a = 0;
This creates a global variable which is also a property of the global object , which we access as window
on browsers (or via this
a global scope, in non-strict code). 这将创建一个全局变量,该变量也是全局对象的属性,我们可以在浏览器中以window
访问该变量(或通过this
window
在非严格代码中通过全局范围访问)。 Unlike some other properties, the property cannot be removed via delete
. 与某些其他属性不同,该属性无法通过delete
。
In specification terms, it creates an identifier binding on the object Environment Record for the global environment . 用规范的术语来说,它在全局环境的对象环境记录上创建一个标识符绑定 。 That makes it a property of the global object because the global object is where identifier bindings for the global environment's object Environment Record are held. 这使它成为全局对象的属性,因为全局对象是全局环境对象环境记录的标识符绑定所在的位置。 This is why the property is non-deletable: It's not just a simple property, it's an identifier binding. 这就是为什么该属性不可删除的原因:它不仅是一个简单的属性,还是一个标识符绑定。
The binding (variable) is defined before the first line of code runs (see "When var
happens" below). 绑定(变量)是在代码的第一行运行之前定义的(请参见下面的“何时发生var
”)。
Note that on IE8 and earlier, the property created on window
is not enumerable (doesn't show up in for..in
statements). 请注意,在IE8和更早版本上,在window
上创建的属性不可枚举 (不会显示在for..in
语句中)。 In IE9, Chrome, Firefox, and Opera, it's enumerable. 在IE9,Chrome,Firefox和Opera中,它是枚举的。
#1.1 let a = 0;
#1.1 let a = 0;
This creates a global variable which is not a property of the global object. 这将创建一个全局变量,该变量不是全局对象的属性。 This is a new thing as of ES2015. 从ES2015开始这是新事物。
In specification terms, it creates an identifier binding on the declarative Environment Record for the global environment rather than the object Environment Record. 用规范术语来说,它在声明性环境记录上为全局环境而不是在对象环境记录上创建标识符绑定。 The global environment is unique in having a split Environment Record, one for all the old stuff that goes on the global object (the object Environment Record) and another for all the new stuff ( let
, const
, and the functions created by class
) that don't go on the global object. 全局环境的独特之处在于它具有分开的环境记录,一个环境记录适用于全局对象上所有的旧内容( 对象环境记录),另一个适用于所有新的内容( let
, const
和由class
创建的函数),不要继续使用全局对象。
The binding is created before any step-by-step code in its enclosing block is executed (in this case, before any global code runs), but it's not accessible in any way until the step-by-step execution reaches the let
statement. 绑定是在执行其封闭块中的任何分步代码之前创建的 (在这种情况下,在任何全局代码运行之前),但是在分步执行到达let
语句之前,它无法以任何方式访问 。 Once execution reaches the let
statement, the variable is accessible. 一旦执行到达let
语句,就可以访问该变量。 (See "When let
and const
happen" below.) (请参见下面的“当let
和const
发生时”。)
#1.2 const a = 0;
#1.2 const a = 0;
Creates a global constant, which is not a property of the global object. 创建一个全局常量,它不是全局对象的属性。
const
is exactly like let
except that you must provide an initializer (the = value
part), and you cannot change the value of the constant once it's created. const
就像let
一样,除了必须提供一个初始化程序( = value
部分),并且一旦创建常量就无法更改其值。 Under the covers, it's exactly like let
but with a flag on the identifier binding saying its value cannot be changed. 在幕后,它就像let
一样,但是在标识符绑定上带有一个标志,表明其值不能更改。 Using const
does three things for you: 使用const
可以为您做三件事:
#2 a = 0;
#2 a = 0;
This creates a property on the global object implicitly . 这将在全局对象上隐式创建一个属性。 As it's a normal property, you can delete it. 由于它是普通属性,因此可以将其删除。 I'd recommend not doing this, it can be unclear to anyone reading your code later. 我建议您不要这样做,以后再阅读您的代码的人可能会不清楚。 If you use ES5's strict mode, doing this (assigning to a non-existent variable) is an error. 如果您使用ES5的严格模式,则执行此操作(将其分配给不存在的变量)是错误的。 It's one of several reasons to use strict mode. 使用严格模式是多种原因之一。
And interestingly, again on IE8 and earlier, the property created not enumerable (doesn't show up in for..in
statements). 有趣的是,再次在IE8和更早版本上,创建的属性不可枚举 (不会出现在for..in
语句中)。 That's odd, particularly given #3 below. 这很奇怪,特别是在下面的#3中。
#3 window.a = 0;
#3 window.a = 0;
This creates a property on the global object explicitly, using the window
global that refers to the global object (on browsers; some non-browser environments have an equivalent global variable, such as global
on NodeJS). 这创建全局对象上的属性明确,使用window
,指的全局对象全局(在浏览器上;一些非浏览器环境具有等同的全局变量,诸如global
上的NodeJS)。 As it's a normal property, you can delete it. 由于它是普通属性,因此可以将其删除。
This property is enumerable, on IE8 and earlier, and on every other browser I've tried. 在IE8和更早版本以及我尝试过的所有其他浏览器上,此属性都是可枚举的。
#4 this.a = 0;
#4 this.a = 0;
Exactly like #3, except we're referencing the global object through this
instead of the global window
. 就像#3一样,除了我们通过this
而不是global window
引用全局对象。 This won't work in strict mode, though, because in strict mode global code, this
doesn't have a reference to the global object (it has the value undefined
instead). 这在严格模式是行不通的,但是,因为在严格模式全局代码, this
不具有全局对象(它的价值的参考undefined
代替)。
What do I mean by "deleting" or "removing" a
? “删除”或“删除” a
是什么意思? Exactly that: Removing the property (entirely) via the delete
keyword: 正是这样:通过delete
关键字完全删除该属性:
window.a = 0;
display("'a' in window? " + ('a' in window)); // displays "true"
delete window.a;
display("'a' in window? " + ('a' in window)); // displays "false"
delete
completely removes a property from an object. delete
完全删除对象的属性。 You can't do that with properties added to window
indirectly via var
, the delete
is either silently ignored or throws an exception (depending on the JavaScript implementation and whether you're in strict mode). 通过var
间接将属性添加到window
,您将无法做到这一点, delete
会被静默忽略或引发异常(取决于JavaScript实现以及您是否处于严格模式)。
Warning : IE8 again (and presumably earlier, and IE9-IE11 in the broken "compatibility" mode): It won't let you delete properties of the window
object, even when you should be allowed to. 警告 :IE8再次出现(可能是更早的版本,而IE9-IE11处于损坏的“兼容性”模式):即使允许,也不允许您删除window
对象的属性。 Worse, it throws an exception when you try ( try this experiment in IE8 and in other browsers). 更糟糕的是,尝试时会引发异常 (在IE8和其他浏览器中尝试此实验 )。 So when deleting from the window
object, you have to be defensive: 因此,从window
对象中删除时,您必须采取防御措施:
try {
delete window.prop;
}
catch (e) {
window.prop = undefined;
}
That tries to delete the property, and if an exception is thrown it does the next best thing and sets the property to undefined
. 尝试删除该属性,如果抛出异常,它将做第二件事,并将属性设置为undefined
。
This only applies to the window
object, and only (as far as I know) to IE8 and earlier (or IE9-IE11 in the broken "compatibility" mode). 这仅适用于window
对象,并且仅(据我所知)适用于IE8和更早的版本(或处于“兼容”模式的IE9-IE11)。 Other browsers are fine with deleting window
properties, subject to the rules above. 其他浏览器可以删除window
属性,但要遵守上述规则。
var
happens 当var
发生时 The variables defined via the var
statement are created before any step-by-step code in the execution context is run, and so the property exists well before the var
statement. 通过var
语句定义的变量是在运行上下文中的任何逐步代码运行之前创建的,因此该属性在var
语句之前就存在。
This can be confusing, so let's take a look: 这可能会造成混淆,因此让我们看一下:
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"
Live example: 现场示例:
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); }
As you can see, the symbol foo
is defined before the first line, but the symbol bar
isn't. 如您所见,符号foo
在第一行之前定义,但符号bar
未定义。 Where the var foo = "f";
其中var foo = "f";
statement is, there are really two things: defining the symbol, which happens before the first line of code is run; 声明实际上有两件事:定义符号,它发生在代码的第一行运行之前; and doing an assignment to that symbol, which happens where the line is in the step-by-step flow. 并对该符号进行赋值,该操作会在分步流程中的直线处发生。 This is known as " var
hoisting" because the var foo
part is moved ("hoisted") to the top of the scope, but the foo = "f"
part is left in its original location. 这被称为“ var
hoisting”,因为var foo
部分已移动(“提升”)到范围的顶部,但是foo = "f"
部分保留在其原始位置。 (See Poor misunderstood var
on my anemic little blog.) (见可怜的误解var
在我的贫血小博客。)
let
and const
happen 当let
和const
发生时 let
and const
are different from var
in a couple of ways. let
和const
在几个方面与var
不同。 The way that's relevant to the question is that although the binding they define is created before any step-by-step code runs, it's not accessible until the let
or const
statement is reached. 与该问题相关的方式是,尽管它们定义的绑定是在任何分步代码运行之前创建的,但是直到到达let
或const
语句之后,才能访问该绑定。
So while this runs: 因此,在运行时:
display(a); // undefined
var a = 0;
display(a); // 0
This throws an error: 这将引发错误:
display(a); // ReferenceError: a is not defined
let a = 0;
display(a);
The other two ways that let
and const
differ from var
, which aren't really relevant to the question, are: let
和const
与var
不同的其他两种方式与问题无关,它们是:
var
always applies to the entire execution context (throughout global code, or throughout function code in the function where it appears), but let
and const
apply only within the block where they appear. var
始终应用于整个执行上下文(遍历全局代码,或出现在函数中的整个函数代码),但let
和const
仅适用于它们出现的块内。 That is, var
has function (or global) scope, but let
and const
have block scope. 也就是说, var
具有函数(或全局)作用域,而let
和const
具有块作用域。
Repeating var a
in the same context is harmless, but if you have let a
(or const a
), having another let a
or a const a
or a var a
is a syntax error. 在相同的上下文中重复var a
是无害的,但是如果let a
(或const a
),则让另一个let a
或const a
或var a
是语法错误。
Here's an example demonstrating that let
and const
take effect immediately in their block before any code within that block runs, but aren't accessible until the let
or const
statement: 这是一个示例,演示let
和const
在该块中的任何代码运行之前立即在其块中生效,但是直到let
或const
语句才可访问:
var a = 0;
console.log(a);
if (true)
{
console.log(a); // ReferenceError: a is not defined
let a = 1;
console.log(a);
}
Note that the second console.log
fails, instead of accessing the a
from outside the block. 请注意,第二个console.log
失败,而不是从块外部访问a
。
window
) 离题:避免使全局对象( window
)混乱 The window
object gets very, very cluttered with properties. window
对象的属性变得非常混乱。 Whenever possible, strongly recommend not adding to the mess. 只要有可能,强烈建议不要增加混乱。 Instead, wrap up your symbols in a little package and export at most one symbol to the window
object. 而是将符号包装在一个小包装中,并将最多一个符号导出到window
对象。 (I frequently don't export any symbols to the window
object.) You can use a function to contain all of your code in order to contain your symbols, and that function can be anonymous if you like: (我经常不将任何符号导出到window
对象。)您可以使用函数包含所有代码以包含符号,并且如果您愿意,该函数可以是匿名的:
(function() {
var a = 0; // `a` is NOT a property of `window` now
function foo() {
alert(a); // Alerts "0", because `foo` can access `a`
}
})();
In that example, we define a function and have it executed right away (the ()
at the end). 在该示例中,我们定义了一个函数并立即执行它(最后是()
)。
A function used in this way is frequently called a scoping function . 以这种方式使用的函数通常称为作用域函数 。 Functions defined within the scoping function can access variables defined in the scoping function because they're closures over that data (see: Closures are not complicated on my anemic little blog). 在作用域函数定义的,因为他们是在该数据关闭的作用域函数可以访问的变量中定义的函数(见: 瓶盖并不复杂在我贫血的小博客)。
Keeping it simple : 保持简单:
a = 0
The code above gives a global scope variable 上面的代码提供了一个全局范围变量
var a = 0;
This code will give a variable to be used in the current scope, and under it 该代码将给出一个变量,该变量将在当前作用域及其下使用
window.a = 0;
This generally is same as the global variable. 这通常与全局变量相同。