Javascript Javascript中变量声明语法的区别(包括全局变量)?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4862193/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Difference between variable declaration syntaxes in Javascript (including global variables)?
提问by Dan
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?
在全球范围内?
回答by T.J. Crowder
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. I've added the fourth way at the end, but inserted the ES2015 ways after #1 (you'll see why), so we have:
还有第四种方式,从 ES2015 (ES6) 开始,还有两种方式。我在最后添加了第四种方式,但在 #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
Those statements explained
这些声明解释了
#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). Unlike some other properties, the property cannot be removed via delete
.
这将创建一个全局变量,它也是global object 的一个属性,我们可以window
在浏览器上访问它(或通过this
全局范围,在非严格代码中)。与其他一些属性不同,该属性不能通过 删除delete
。
In specification terms, it creates an identifier bindingon the object Environment Recordfor 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). In IE9, Chrome, Firefox, and Opera, it's enumerable.
请注意,在 IE8 及更早版本上,创建于的属性window
不可枚举(不显示在for..in
语句中)。在 IE9、Chrome、Firefox 和 Opera 中,它是可枚举的。
#1.1 let a = 0;
#1.1 let a = 0;
This creates a global variable which is nota property of the global object. This is a new thing as of ES2015.
这将创建一个全局变量,它不是全局对象的属性。这是 ES2015 的新事物。
In specification terms, it creates an identifier binding on the declarativeEnvironment Record for the global environment rather than the objectEnvironment 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 objectEnvironment 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 createdbefore any step-by-step code in its enclosing block is executed (in this case, before any global code runs), but it's not accessiblein any way until the step-by-step execution reaches the let
statement. Once execution reaches the let
statement, the variable is accessible. (See "When let
and const
happen" below.)
绑定是在执行其封闭块中的任何分步代码之前(在这种情况下,在任何全局代码运行之前)创建的,但在分步执行到达语句之前无法以任何方式访问它let
。一旦执行到达let
语句,就可以访问该变量。(请参阅下面的“何时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. Under the covers, it's exactly like let
but with a flag on the identifier binding saying its value cannot be changed. Using const
does three things for you:
const
完全一样,let
只是您必须提供一个初始化程序(= value
部分),并且一旦创建常量就无法更改其值。在幕后,它let
与标识符绑定上的标志完全一样,但表示其值不能更改。使用const
可以为您做三件事:
- Makes it a parse-time error if you try to assign to the constant.
- Documents its unchanging nature for other programmers.
- Lets the JavaScript engine optimize on the basis that it won't change.
- 如果您尝试分配给常量,则会导致解析时错误。
- 为其他程序员记录其不变的性质。
- 让 JavaScript 引擎在它不会改变的基础上进行优化。
#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 notdoing 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. It's one of several reasons to use strict mode.
这会隐式地在全局对象上创建一个属性。由于它是一个普通属性,您可以将其删除。我建议不要这样做,以后阅读您的代码的任何人都可能不清楚。如果你使用 ES5 的严格模式,这样做(赋值给一个不存在的变量)是一个错误。这是使用严格模式的几个原因之一。
And interestingly, again on IE8 and earlier, the property created not enumerable(doesn't show up in for..in
statements). That's odd, particularly given #3 below.
有趣的是,同样在 IE8 及更早版本上,创建的属性不可枚举(不显示在for..in
语句中)。这很奇怪,特别是考虑到下面的 #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). As it's a normal property, you can delete it.
这会使用window
引用全局对象的 global 显式地在全局对象上创建一个属性(在浏览器上;某些非浏览器环境具有等效的全局变量,例如global
在 NodeJS 上)。由于它是一个普通属性,您可以将其删除。
This property isenumerable, 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
. 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).
与#3 完全一样,除了我们通过this
而不是global 引用全局对象window
。但是,这在严格模式下this
不起作用,因为在严格模式下全局代码没有对全局对象的引用(它具有值undefined
)。
Deleting properties
删除属性
What do I mean by "deleting" or "removing" a
? Exactly that: Removing the property (entirely) via the delete
keyword:
我所说的“删除”或“移除”是什么意思a
?正是这样:通过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. 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).
delete
从对象中完全删除属性。你不能做到这一点与特性加入到window
通过间接var
时,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. Worse, it throws an exceptionwhen you try (try this experimentin IE8 and in other browsers). So when deleting from the window
object, you have to be defensive:
警告:IE8 再次(大概更早,IE9-IE11 处于破坏的“兼容”模式):它不会让您删除window
对象的属性,即使您应该被允许。更糟糕的是,它会在您尝试时抛出异常(在 IE8 和其他浏览器中尝试此实验)。所以当从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 onlyapplies to the window
object, and only (as far as I know) to IE8 and earlier (or IE9-IE11 in the broken "compatibility" mode). Other browsers are fine with deleting window
properties, subject to the rules above.
这仅适用于window
对象,并且仅(据我所知)适用于 IE8 及更早版本(或 IE9-IE11 处于损坏的“兼容”模式)。window
根据上述规则,其他浏览器可以删除属性。
When var
happens
什么时候var
发生
The variables defined via the var
statement are created before anystep-by-step code in the execution context is run, and so the property exists well beforethe 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. Where the 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. (See Poor misunderstood var
on my anemic little blog.)
如您所见,符号foo
在第一行之前定义,但符号bar
不是。var foo = "f";
语句在哪里,实际上有两件事:定义符号,它发生在第一行代码运行之前;并对该符号进行赋值,这发生在分步流程中该行所在的位置。这被称为“var
提升”,因为var foo
部件被移动(“提升”)到范围的顶部,但foo = "f"
部件留在其原始位置。(请参阅我贫血的小博客上的被误解的可怜var
。)
When let
and const
happen
当let
和const
发生
let
and const
are different from var
in a couple of ways. 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 accessibleuntil the let
or const
statement is reached.
let
并且在几个方面const
有所不同var
。与问题相关的方式是,尽管它们定义的绑定是在任何分步代码运行之前创建的,但在到达let
orconst
语句之前无法访问它。
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), butlet
andconst
apply only within the blockwhere they appear. That is,var
has function (or global) scope, butlet
andconst
have block scope.Repeating
var a
in the same context is harmless, but if you havelet a
(orconst a
), having anotherlet a
or aconst a
or avar a
is a syntax error.
var
始终适用于整个执行上下文(整个全局代码,或者贯穿在它出现的功能函数代码),但let
并const
仅在适用块在那里出现。也就是说,var
具有功能(或全球)的范围,但let
并const
有块范围。var a
在同一上下文中重复是无害的,但如果您有let a
(或const a
),则有另一个let a
或 aconst a
或 avar 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
orconst
语句之前无法访问:
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
从块外部访问。
Off-topic: Avoid cluttering the global object (window
)
题外话:避免混乱全局对象 ( window
)
The window
object gets very, very cluttered with properties. Whenever possible, strongly recommend not adding to the mess. Instead, wrap up your symbols in a little package and export at mostone symbol to the window
object. (I frequently don't export anysymbols 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
物体变得非常,非常混乱与性质。只要有可能,强烈建议不要添加到混乱中。相反,将您的符号包装在一个小包中,并最多将一个符号导出到window
对象。(我经常不向对象导出任何符号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 closuresover that data (see: Closures are not complicatedon my anemic little blog).
以这种方式使用的函数通常称为作用域函数。在作用域函数定义的,因为他们是作用域函数可以访问的变量中定义的函数关闭了数据(见:瓶盖并不复杂在我贫血的小博客)。
回答by Umair Jabbar
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.
这通常与全局变量相同。
回答by Cody
<title>Index.html</title>
<script>
var varDeclaration = true;
noVarDeclaration = true;
window.hungOnWindow = true;
document.hungOnDocument = true;
</script>
<script src="external.js"></script>
/* 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 声明'
回答by robe007
Bassed on the excellent answer of T.J. Crowder: (Off-topic: Avoid cluttering window
)
基于TJ Crowder的出色回答:(题外话:避免混乱window
)
This is an example of his idea:
这是他的想法的一个例子:
Html
html
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="init.js"></script>
<script type="text/javascript">
MYLIBRARY.init(["firstValue", 2, "thirdValue"]);
</script>
<script src="script.js"></script>
</head>
<body>
<h1>Hello !</h1>
</body>
</html>
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
脚本.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. Hope it help !
这是plnkr。希望有帮助!
回答by Raynos
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. This is an issue with IE's notorious broken interpreter. This bug does sound familiar so it's probably true.
正如@AvianMoncellor 所提到的,存在一个 IE 错误,var a = foo
仅声明了一个全局文件范围。这是 IE 臭名昭著的破损解释器的一个问题。这个错误听起来很熟悉,所以它可能是真的。
So stick to window.globalName = someLocalpointer
所以坚持 window.globalName = someLocalpointer