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

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 是 a = 0;

这创建了一个全局变量,它也是全局对象的一个属性,我们可以在浏览器上作为窗口访问它(或者在非严格代码中通过这个全局作用域)。与其他一些属性不同,该属性不能通过delete删除。

在规范术语中,它为全局环境的对象环境记录创建标识符绑定。这使得它成为全局对象的属性,因为全局对象是保存全局环境的对象environment Record的标识符绑定的地方。这就是为什么属性是不可删除的:它不仅仅是一个简单的属性,它是一个标识符绑定。

绑定(变量)在第一行代码运行之前定义(请参阅下面的“当var发生时”)。

注意,在IE8和更早的版本中,在window上创建的属性是不可枚举的(不会出现在for..in语句中)。在IE9、Chrome、Firefox和Opera中,它是可枚举的。


#1.1 let a = 0;

这将创建一个全局变量,它不是全局对象的属性。这是ES2015的新功能。

在规范术语中,它为全局环境而不是对象环境记录在声明性环境记录上创建标识符绑定。全局环境的独特之处在于它有一个分离的环境记录,一个用于保存在全局对象上的所有旧东西(对象环境记录),另一个用于保存不在全局对象上的所有新东西(let、const和类创建的函数)。

绑定是在其外围块中的任何逐步代码执行之前创建的(在本例中,在任何全局代码运行之前),但是在逐步执行到达let语句之前,它不能以任何方式访问。一旦执行到let语句,变量就可以访问了。(请参阅下面的“When let and const happen”。)


#1.2 const a = 0;

创建一个全局常量,它不是全局对象的属性。

Const与let完全相似,除了必须提供初始化式(= value部分),并且常量创建后不能更改它的值。在本质上,它与let完全相似,但在标识符绑定上有一个标志,表示其值不能更改。使用const可以做三件事:

使它成为一个解析时错误,如果你试图分配给常数。 为其他程序员记录其不变的性质。 让JavaScript引擎在不变的基础上进行优化。


#2 a = 0;

这将隐式地在全局对象上创建一个属性。因为它是一个普通的属性,所以您可以删除它。我建议不要这样做,因为以后阅读代码的人可能会看不清楚。如果你使用ES5的严格模式,这样做(分配给一个不存在的变量)是一个错误。这是使用严格模式的原因之一。

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


3号窗口。A = 0;

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

这个属性是可枚举的,在IE8和更早的版本,以及我尝试过的其他浏览器上都是如此。


# 4。A = 0;

与第3条完全相同,只是我们通过this而不是全局窗口引用全局对象。但这在严格模式下行不通,因为在严格模式全局代码中,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从对象中完全删除一个属性。您不能通过var间接地将属性添加到窗口中,删除操作要么被静默忽略,要么抛出异常(取决于JavaScript实现以及是否处于严格模式)。

警告:还是IE8(可能更早,IE9-IE11的“兼容性”模式已经坏了):它不允许你删除窗口对象的属性,即使你应该被允许这样做。更糟糕的是,当你尝试时,它会抛出一个异常(在IE8和其他浏览器中尝试这个实验)。所以当从窗口对象中删除时,你必须是防御性的:

try {
    delete window.prop;
}
catch (e) {
    window.prop = undefined;
}

尝试删除属性,如果抛出异常,它会做下一个最好的事情,并将属性设置为未定义。

这只适用于窗口对象,并且仅(据我所知)适用于IE8和更早的版本(或在破碎的“兼容”模式下的IE9-IE11)。其他浏览器可以根据上述规则删除窗口属性。


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

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


当let和const发生时

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

所以当它运行时:

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或const a或var a是一个语法错误。

下面是一个示例,演示了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);
}

注意,第二个console.log失败了,而不是从块外部访问a。


跑题:避免混淆全局对象(窗口)

窗口对象的属性变得非常混乱。只要有可能,强烈建议不要再添乱了。相反,将符号打包到一个小包中,最多导出一个符号到窗口对象。(我经常不向窗口对象导出任何符号。)你可以使用一个函数来包含你所有的代码,以包含你的符号,如果你喜欢,这个函数可以是匿名的:

(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,因为你设置的值是一个未声明的变量。

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

(function() {
   // do stuff locally

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

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

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

所以还是靠窗户吧。globalName = somlocalpointer

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

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

这创建了一个全局变量,它也是全局对象的一个属性,我们可以在浏览器上作为窗口访问它(或者在非严格代码中通过这个全局作用域)。与其他一些属性不同,该属性不能通过delete删除。

在规范术语中,它为全局环境的对象环境记录创建标识符绑定。这使得它成为全局对象的属性,因为全局对象是保存全局环境的对象environment Record的标识符绑定的地方。这就是为什么属性是不可删除的:它不仅仅是一个简单的属性,它是一个标识符绑定。

绑定(变量)在第一行代码运行之前定义(请参阅下面的“当var发生时”)。

注意,在IE8和更早的版本中,在window上创建的属性是不可枚举的(不会出现在for..in语句中)。在IE9、Chrome、Firefox和Opera中,它是可枚举的。


#1.1 let a = 0;

这将创建一个全局变量,它不是全局对象的属性。这是ES2015的新功能。

在规范术语中,它为全局环境而不是对象环境记录在声明性环境记录上创建标识符绑定。全局环境的独特之处在于它有一个分离的环境记录,一个用于保存在全局对象上的所有旧东西(对象环境记录),另一个用于保存不在全局对象上的所有新东西(let、const和类创建的函数)。

绑定是在其外围块中的任何逐步代码执行之前创建的(在本例中,在任何全局代码运行之前),但是在逐步执行到达let语句之前,它不能以任何方式访问。一旦执行到let语句,变量就可以访问了。(请参阅下面的“When let and const happen”。)


#1.2 const a = 0;

创建一个全局常量,它不是全局对象的属性。

Const与let完全相似,除了必须提供初始化式(= value部分),并且常量创建后不能更改它的值。在本质上,它与let完全相似,但在标识符绑定上有一个标志,表示其值不能更改。使用const可以做三件事:

使它成为一个解析时错误,如果你试图分配给常数。 为其他程序员记录其不变的性质。 让JavaScript引擎在不变的基础上进行优化。


#2 a = 0;

这将隐式地在全局对象上创建一个属性。因为它是一个普通的属性,所以您可以删除它。我建议不要这样做,因为以后阅读代码的人可能会看不清楚。如果你使用ES5的严格模式,这样做(分配给一个不存在的变量)是一个错误。这是使用严格模式的原因之一。

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


3号窗口。A = 0;

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

这个属性是可枚举的,在IE8和更早的版本,以及我尝试过的其他浏览器上都是如此。


# 4。A = 0;

与第3条完全相同,只是我们通过this而不是全局窗口引用全局对象。但这在严格模式下行不通,因为在严格模式全局代码中,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从对象中完全删除一个属性。您不能通过var间接地将属性添加到窗口中,删除操作要么被静默忽略,要么抛出异常(取决于JavaScript实现以及是否处于严格模式)。

警告:还是IE8(可能更早,IE9-IE11的“兼容性”模式已经坏了):它不允许你删除窗口对象的属性,即使你应该被允许这样做。更糟糕的是,当你尝试时,它会抛出一个异常(在IE8和其他浏览器中尝试这个实验)。所以当从窗口对象中删除时,你必须是防御性的:

try {
    delete window.prop;
}
catch (e) {
    window.prop = undefined;
}

尝试删除属性,如果抛出异常,它会做下一个最好的事情,并将属性设置为未定义。

这只适用于窗口对象,并且仅(据我所知)适用于IE8和更早的版本(或在破碎的“兼容”模式下的IE9-IE11)。其他浏览器可以根据上述规则删除窗口属性。


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

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


当let和const发生时

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

所以当它运行时:

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或const a或var a是一个语法错误。

下面是一个示例,演示了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);
}

注意,第二个console.log失败了,而不是从块外部访问a。


跑题:避免混淆全局对象(窗口)

窗口对象的属性变得非常混乱。只要有可能,强烈建议不要再添乱了。相反,将符号打包到一个小包中,最多导出一个符号到窗口对象。(我经常不向窗口对象导出任何符号。)你可以使用一个函数来包含你所有的代码,以包含你的符号,如果你喜欢,这个函数可以是匿名的:

(function() {
    var a = 0; // `a` is NOT a property of `window` now

    function foo() {
        alert(a);   // Alerts "0", because `foo` can access `a`
    }
})();

在这个例子中,我们定义了一个函数,并让它立即执行(末尾的())。

以这种方式使用的函数通常称为作用域函数。在作用域函数中定义的函数可以访问作用域函数中定义的变量,因为它们是数据上的闭包(参见:闭包并不复杂)。

基于T.J.克劳德的精彩回答:(跑题:避免乱扔窗户)

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

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

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。希望能有所帮助!

<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

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

保持简单:

a = 0

上面的代码给出了一个全局作用域变量

var a = 0;

这段代码将给出一个在当前作用域中使用的变量

window.a = 0;

这通常与全局变量相同。