Javascript中变量声明语法的区别(包括全局变量)?

声明一个变量有什么区别吗:

var a=0; //1

...这种方式:

a=0; //2

或:

window.a=0; //3

在全球范围内?

268982 次浏览

在全局范围内没有语义差异。

但你真的应该避免a=0,因为你将一个值设置为一个未声明的变量。

也可以使用闭包来避免编辑全局作用域

(function() {
// do stuff locally


// Hoist something to global scope
window.someGlobal = someLocal
}());

当绝对必要时,总是使用闭包并始终提升到全局范围。无论如何,您应该在大部分通信中使用异步事件处理。

正如@AvianMoncellor提到的,有一个IE错误,var a = foo只声明了一个全局文件作用域。这是IE臭名昭著的坏解释器的一个问题。这个错误听起来很熟悉,所以可能是真的。

所以坚持window.globalName = someLocalpointer

是的,有一些区别,尽管在实际应用中,它们通常不是很大的区别。

还有第四种方法,到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;

这将创建一个全局变量,它也是< em >全局对象< / em >的属性,我们在浏览器中以window的形式访问它(或在非严格代码中通过this的全局作用域访问)。与其他一些属性不同,该属性不能通过delete删除。

在规范术语中,它为全球环境< em > < / em >/a> . object 环境记录 . object 隐式< em > < / em >上创建一个属性。因为它是一个普通的属性,所以您可以删除它。我建议这样做,它可能对以后阅读你的代码的人不清楚。如果你使用ES5的严格模式,这样做(分配给一个不存在的变量)是一个错误。这是使用严格模式的原因之一。

有趣的是,在IE8和更早的版本中,属性创建的不是可列举的(不会出现在for..in语句中)。这很奇怪,尤其是考虑到下面的第三条。


# 3 window.a = 0;

这将显式地在全局对象上创建一个属性,使用引用全局对象的window全局变量(在浏览器上;一些非浏览器环境有一个等效的全局变量,比如NodeJS上的global)。因为它是一个普通的属性,所以您可以删除它。

此属性可枚举,在IE8及更早版本上,以及在我尝试过的所有其他浏览器上。


# 4 this.a = 0;

与第3条完全相同,只是我们通过this而不是全局window引用全局对象。不过,这在严格模式下行不通,因为在严格模式全局代码中,this没有对全局对象的引用(它的值是undefined)。


删除属性

我说的“删除”是什么意思?或“;removing"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完全从对象中移除一个属性。你不能通过var间接地将属性添加到window中,delete要么被默默地忽略,要么抛出异常(取决于JavaScript实现以及是否处于严格模式)。

警告:再次使用IE8(可能更早,和IE9-IE11在破碎的“兼容性”;mode):它不会让你删除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"

生活例子:

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);
}

如你所见,符号foo在第一行之前定义,但符号bar没有。var foo = "f";语句所在的地方,实际上有两件事:定义符号,这发生在第一行代码运行之前;然后对那个符号进行赋值,这发生在分步流程中这条线的位置。这就是所谓的“var吊装”;因为var foo部分被移动("提升")到作用域的顶部,但foo = "f"部分保留在原始位置。(见我贫血的小博客上的可怜的误解var。)


letconst发生时

letconst在几个方面与var不同。与问题相关的方式是,尽管它们定义的绑定是在任何逐步代码运行之前创建的,但直到到达letconst语句时才会是可访问的

所以当它运行时:

display(a);    // undefined
var a = 0;
display(a);    // 0

这会抛出一个错误:

display(a);    // ReferenceError: a is not defined
let a = 0;
display(a);

letconstvar的另外两种不同之处是:

  1. var总是应用于整个执行上下文(在全局代码中,或在它出现的函数中的函数代码中),但letconst只应用于它们出现的中。也就是说,var具有函数(或全局)作用域,而letconst具有块作用域。

  2. 在相同的上下文中重复var a是无害的,但如果你有let a(或const a),有另一个let aconst avar a是语法错误。

下面是一个示例,演示了letconst在其块内的任何代码运行之前立即生效,但直到letconst语句才可访问:

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

是否有一个全局对象,所有变量默认挂起?如:“全局。束射功率管宣言”

基于T.J.克劳德的优秀答案:(跑题:避免混淆window)

下面是他想法的一个例子:

超文本标记语言

<!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];
}
};
}());

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);

这里是plnkr。希望能有所帮助!