T.J*_*der 551

是的,有一些差异,但实际上它们通常不是大的.

还有第四种方式,从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
Run Code Online (Sandbox Code Playgroud)

这些陈述解释了

#1 var a = 0;

这将创建一个全局变量,该变量也是全局对象的属性,我们可以window在浏览器上(或通过this全局范围,非严格代码)访问该属性.与其他一些属性不同,该属性无法通过删除delete.

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

绑定(变量)是在第一行代码运行之前定义的(参见var下面的" 发生时").

请注意,在IE8及更早版本中,创建的属性window不可枚举(不会显示在for..in语句中).在IE9,Chrome,Firefox和Opera中,它是可枚举的.


#1.1 let a = 0;

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

在规范术语中,它在全局环境的声明性环境记录上创建标识符绑定,而不是对象环境记录.全球环境是具有开裂环境记录,一个对所有旧的东西就是那张在全局对象(独特的对象为所有新的东西,环境记录),另一个(let,const,和所创造的功能class)不继续全球对象.

是结合创建执行在它的外围块中的任何一步一步的代码之前(在这种情况下,全球任何代码运行之前),但它不是访问,直到一步一步的执行到达以任何方式let声明.一旦执行到达let语句,就可以访问该变量.(见"当letconst发生"的.)


#1.2 const a = 0;

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

const酷似let除了你必须提供一个初始化(的= value一部分),并且一旦创建它,你不能改变常量的值.在封面下,它完全像是let在标识符绑定上有一个标志,说它的值不能改变.使用const为您做三件事:

  1. 如果您尝试分配常量,则会使其成为分析时错误.
  2. 记录其为其他程序员不变的本质.
  3. 让JavaScript引擎在不会改变的基础上进行优化.

#2 a = 0;

这会隐式地在全局对象上创建一个属性.由于它是普通属性,您可以删除它.我建议要这样做,以后读取你的代码的任何人都不清楚.如果使用ES5的严格模式,执行此操作(分配给不存在的变量)是一个错误.这是使用严格模式的几个原因之一.

有趣的是,再次在IE8和更早版本中,属性创建不可枚举(不会显示在for..in语句中).这很奇怪,特别是下面的#3.


#3 window.a = 0;

这将使用window引用全局对象的全局(在浏览器上;某些非浏览器环境具有等效的全局变量,例如global在NodeJS上)显式地在全局对象上创建属性.由于它是普通属性,您可以删除它.

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


#4 this.a = 0;

完全像#3,除了我们通过this而不是全局引用全局对象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"
Run Code Online (Sandbox Code Playgroud)

delete从对象中完全删除属性.你不能做到这一点与特性添加到window间接地通过var时,delete要么悄悄地忽略或抛出一个异常(取决于JavaScript实现,以及是否你在严格模式).

警告:IE8再次(大概早些时候,IE9-IE11处于破坏的"兼容性"模式):它不会让你删除window对象的属性,即使你应该被允许.更糟糕的是,它会在您尝试时抛出异常(在IE8和其他浏览器中尝试此实验).因此,当从window对象中删除时,您必须是防御性的:

try {
    delete window.prop;
}
catch (e) {
    window.prop = undefined;
}
Run Code Online (Sandbox Code Playgroud)

这会尝试删除该属性,如果抛出异常,它会执行下一个最好的操作并将属性设置为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"
Run Code Online (Sandbox Code Playgroud)

实例:

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);
}
Run Code Online (Sandbox Code Playgroud)

如您所见,符号foo在第一行之前定义,但符号bar不是.在var foo = "f";语句所在的位置,实际上有两件事:定义符号,该符号在第一行代码运行之前发生; 并对该符号进行分配,该分配发生在该行逐步流程中.这被称为" var提升",因为var foo零件被移动("提升")到示波器的顶部,但foo = "f"零件保留在其原始位置.(看到我在贫穷的小博客上被误解var了.)


letconst发生

let并且在几个方面const有所不同var.与问题相关的方式是尽管它们定义的绑定是在任何逐步代码运行之前创建的,但在达到或者语句之前它是不可访问的.letconst

这样运行时:

display(a);    // undefined
var a = 0;
display(a);    // 0
Run Code Online (Sandbox Code Playgroud)

这会引发错误:

display(a);    // ReferenceError: a is not defined
let a = 0;
display(a);
Run Code Online (Sandbox Code Playgroud)

其他两种方式let,并const从不同的var,这是不是真正的问题有关,主要有:

  1. var始终适用于整个执行上下文(整个全局代码,或者贯穿在它出现的功能函数代码),但letconst仅在适用在那里出现.也就是说,var具有功能(或全球)的范围,但letconst有块范围.

  2. var a在相同的上下文中重复是无害的,但是如果你有let a(或const a),则有另一个let a或一个const a或一个var 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);
}
Run Code Online (Sandbox Code Playgroud)

请注意,第二个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`
    }
})();
Run Code Online (Sandbox Code Playgroud)

在那个例子中,我们定义一个函数并立即执行它(()最后).

以这种方式使用的函数通常称为作用域函数.作用域函数中定义的,因为他们可以访问作用域函数中定义的变量的函数关闭了数据(见:瓶盖并不复杂在我贫血的小博客).


Uma*_*bar 40

保持简单:

a = 0
Run Code Online (Sandbox Code Playgroud)

上面的代码给出了一个全局范围变量

var a = 0;
Run Code Online (Sandbox Code Playgroud)

此代码将给出一个在当前作用域中使用的变量,并在其下面

window.a = 0;
Run Code Online (Sandbox Code Playgroud)

这通常与全局变量相同.

  • 中间的一个被认为是在一个函数中使用,如果在主范围内使用它们,它们都是相同的.在函数中使用var是我的假设 (4认同)
  • @Umair:*"在函数中使用var是我的假设"*啊,好的.但那不是问题.问题非常明确地说*"在全球范围内"*.如果你要改变假设(这是公平的,扩展和解释一个更普遍的观点),你需要明确你正在做的答案. (4认同)
  • @Umair:*"全局本身意味着您可以在任何地方访问/读取/写入变量"*对.再一次,你似乎把第一个和最后一个称为"全局"而不是中间,当然它们不是. (3认同)

Cod*_*ody 10

<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
Run Code Online (Sandbox Code Playgroud)

是否存在一个全局对象,默认情况下所有变量都挂起?例如:'globals.noVar声明'


rob*_*007 7

基于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>
Run Code Online (Sandbox Code Playgroud)

init.js(根据这个答案)

var MYLIBRARY = MYLIBRARY || (function(){
    var _args = {}; // private

    return {
        init : function(Args) {
            _args = Args;
            // some other initialising
        },
        helloWorld : function(i) {
            return _args[i];
        }
    };
}());
Run Code Online (Sandbox Code Playgroud)

的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);
Run Code Online (Sandbox Code Playgroud)

这是plnkr.希望它有所帮助!


Ray*_*nos 5

在全球范围内,没有语义差异.

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

还可以使用闭包来避免编辑全局范围

(function() {
   // do stuff locally

   // Hoist something to global scope
   window.someGlobal = someLocal
}());
Run Code Online (Sandbox Code Playgroud)

始终使用闭合装置,并在绝对必要时始终提升到全球范围.无论如何,您应该使用异步事件处理进行大部分通信.

正如@AvianMoncellor所提到的那样,IE bug var a = foo只是声明了一个全局的文件范围.这是IE臭名昭着的破解翻译的问题.这个错误听起来很熟悉,所以它可能是真的.

所以坚持下去 window.globalName = someLocalpointer

  • *"在全球范围内,没有语义差异."*实际上,存在巨大的语义差异,属性定义的机制完全不同 - 但实际上它归结为只有很小的*实际*差异(因为你不能"删除"`var`). (2认同)