声明变量有什么区别:
var a=0; //1
...这边走:
a=0; //2
...或者:
window.a=0; //3
在全球范围内?
声明变量有什么区别:
var a=0; //1
...这边走:
a=0; //2
...或者:
window.a=0; //3
在全球范围内?
是的,有一些差异,但实际上它们通常不是很大。
还有第四种方式,从 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
#1 var a = 0;
这将创建一个全局变量,它也是global object 的一个属性,我们可以像window
在浏览器上一样访问它(或通过this
全局范围,在非严格代码中)。与其他一些属性不同,该属性不能通过 删除delete
。
在规范方面,它为全局环境在对象环境记录上创建标识符绑定。这使它成为全局对象的一个属性,因为全局对象是保存全局环境对象环境记录的标识符绑定的地方。这就是属性不可删除的原因:它不仅仅是一个简单的属性,它还是一个标识符绑定。
绑定(变量)是在第一行代码运行之前定义的(参见var
下面的“何时发生”)。
请注意,在 IE8 及更早版本上,创建于的属性window
不可枚举(不显示在for..in
语句中)。在 IE9、Chrome、Firefox 和 Opera 中,它是可枚举的。
#1.1 let a = 0;
这将创建一个全局变量,它不是全局对象的属性。这是 ES2015 的新事物。
在规范方面,它为全局环境而不是对象环境记录在声明性环境记录上创建标识符绑定。全球环境是具有开裂环境记录,一个对所有旧的东西就是那张在全局对象(独特的对象为所有新的东西,环境记录),另一个(,,和所创造的功能)不继续全局对象。let
const
class
绑定是在执行其封闭块中的任何分步代码之前(在这种情况下,在任何全局代码运行之前)创建的,但在分步执行到达语句之前无法以任何方式访问它let
。一旦执行到达let
语句,就可以访问该变量。(请参阅下面的“何时let
和const
发生”。)
#1.2 const a = 0;
创建一个全局常量,它不是全局对象的属性。
const
完全一样,let
只是您必须提供一个初始化程序(= value
部分),并且一旦创建常量就不能更改其值。在幕后,它let
与标识符绑定上的标志完全一样,但表示其值不能更改。使用const
可以为您做三件事:
#2 a = 0;
这会隐式地在全局对象上创建一个属性。由于它是一个普通属性,您可以将其删除。我建议不要这样做,以后阅读您的代码的任何人都可能不清楚。如果您使用 ES5 的严格模式,则执行此操作(分配给不存在的变量)是错误的。这是使用严格模式的几个原因之一。
有趣的是,同样在 IE8 和更早版本上,创建的属性不可枚举(不显示在for..in
语句中)。这很奇怪,特别是考虑到下面的#3。
#3 window.a = 0;
这会使用window
引用全局对象的 global 显式地在全局对象上创建一个属性(在浏览器上;一些非浏览器环境具有等效的全局变量,例如global
在 NodeJS 上)。由于它是一个普通属性,您可以将其删除。
此属性是可枚举的,在 IE8 及更早版本以及我尝试过的所有其他浏览器上。
#4 this.a = 0;
与#3 完全一样,除了我们通过this
而不是global 引用全局对象window
。但是,这在严格模式下this
不起作用,因为在严格模式下全局代码没有对全局对象的引用(它具有值undefined
)。
我所说的“删除”或“移除”是什么意思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
从对象中完全删除一个属性。你不能做到这一点与特性加入到window
通过间接var
时,delete
要么悄悄地忽略或抛出一个异常(取决于JavaScript实现,以及是否你在严格模式)。
警告:再次使用 IE8(可能更早,并且 IE9-IE11 处于损坏的“兼容”模式):它不会让您删除window
对象的属性,即使您应该被允许。更糟糕的是,它会在您尝试时抛出异常(在 IE8 和其他浏览器中尝试此实验)。所以当从window
对象中删除时,你必须是防御性的:
try {
delete window.prop;
}
catch (e) {
window.prop = undefined;
}
这会尝试删除该属性,如果抛出异常,它会执行下一个最好的操作并将该属性设置为undefined
.
这仅适用于window
对象,并且(据我所知)仅适用于IE8 及更早版本(或 IE9-IE11 处于损坏的“兼容”模式)。window
根据上述规则,其他浏览器可以删除属性。
var
发生通过var
语句定义的变量是在执行上下文中的任何分步代码运行之前创建的,因此该属性存在于语句之前var
。
这可能会令人困惑,所以让我们来看看:
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"
现场示例:
如您所见,符号foo
在第一行之前定义,但符号bar
不是。var foo = "f";
语句在哪里,实际上有两件事:定义符号,它发生在第一行代码运行之前;并对该符号进行赋值,这发生在分步流程中该行所在的位置。这称为“var
提升”,因为var foo
零件被移动(“提升”)到示波器的顶部,但foo = "f"
零件仍留在其原始位置。(请参阅我贫血的小博客上的被误解的可怜var
。)
let
和const
发生let
并且在几个方面const
有所不同var
。与问题相关的方式是,尽管它们定义的绑定是在任何分步代码运行之前创建的,但在到达let
orconst
语句之前无法访问它。
所以当它运行时:
display(a); // undefined
var a = 0;
display(a); // 0
这会引发错误:
display(a); // ReferenceError: a is not defined
let a = 0;
display(a);
let
与 和const
不同的另外两种var
与问题无关的方式是:
var
始终适用于整个执行上下文(整个全局代码,或者贯穿在它出现的功能函数代码),但let
并const
仅在适用块在那里出现。也就是说,var
具有功能(或全球)的范围,但let
并const
有块范围。
var a
在同一上下文中重复是无害的,但如果您有let a
(或const a
),则有另一个let a
或 aconst a
或 avar a
是语法错误。
这是一个示例,演示了这一点,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);
}
请注意,第二个console.log
失败,而不是a
从块外部访问。
window
)该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`
}
})();
在那个例子中,我们定义了一个函数并让它立即执行(()
最后)。
以这种方式使用的函数通常称为作用域函数。在作用域函数定义的,因为他们是作用域函数可以访问的变量中定义的函数关闭了数据(见:瓶盖并不复杂在我贫血的小博客)。
保持简单:
a = 0
上面的代码给出了一个全局作用域变量
var a = 0;
这段代码将给出一个在当前作用域中使用的变量,在它之下
window.a = 0;
这通常与全局变量相同。
<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
是否有一个全局对象默认所有变量都被挂起?例如:'globals.noVar 声明'
基于TJ Crowder的出色回答:(题外话:避免混乱window
)
这是他的想法的一个例子:
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(基于这个答案)
var MYLIBRARY = MYLIBRARY || (function(){
var _args = {}; // private
return {
init : function(Args) {
_args = Args;
// some other initialising
},
helloWorld : function(i) {
return _args[i];
}
};
}());
脚本.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);
这是plnkr。希望有帮助!
在全局范围内没有语义差异。
但是您确实应该避免,a=0
因为您将值设置为未声明的变量。
还可以使用闭包来完全避免编辑全局作用域
(function() {
// do stuff locally
// Hoist something to global scope
window.someGlobal = someLocal
}());
始终使用闭包,并在绝对必要时始终将其提升到全局范围。无论如何,您应该在大部分通信中使用异步事件处理。
正如@AvianMoncellor 所提到的,存在一个 IE 错误,var a = foo
仅声明了一个全局文件范围。这是 IE 臭名昭著的破损解释器的一个问题。这个错误听起来很熟悉,所以它可能是真的。
所以坚持 window.globalName = someLocalpointer