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

本文翻译自:Difference between variable declaration syntaxes in Javascript (including global variables)?

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? 在全球范围内?


#1楼

参考:https://stackoom.com/question/koSt/Javascript中的变量声明语法-包括全局变量-之间的区别


#2楼

<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声明”


#3楼

Bassed on the excellent answer of TJ 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 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);

Here's the plnkr . 这是plnkr Hope it help ! 希望对您有所帮助!


#4楼

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. 正如@AvianMoncellor提到的那样,有一个IE错误,其中var a = foo仅声明了文件范围的全局值。 This is an issue with IE's notorious broken interpreter. 这是IE臭名昭著的解释器的问题。 This bug does sound familiar so it's probably true. 这个错误听起来确实很熟悉,所以可能是事实。

So stick to window.globalName = someLocalpointer 所以坚持window.globalName = someLocalpointer


#5楼

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. 还有第四种方法,从ES2015(ES6)开始,还有另外两种方法。 I've added the fourth way at the end, but inserted the ES2015 ways after #1 (you'll see why), so we have: 我在末尾添加了第四种方式,但是在#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). 这将创建一个全局变量,该变量也是全局对象的属性,我们可以在浏览器中以window访问该变量(或通过this window在非严格代码中通过全局范围访问)。 Unlike some other properties, the property cannot be removed via delete . 与某些其他属性不同,该属性无法通过delete

In specification terms, it creates an identifier binding on the object Environment Record for 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). 请注意,在IE8和更早版本上,在window上创建的属性不可枚举 (不会显示在for..in语句中)。 In IE9, Chrome, Firefox, and Opera, it's enumerable. 在IE9,Chrome,Firefox和Opera中,它是枚举的。


#1.1 let a = 0; #1.1 let a = 0;

This creates a global variable which is not a property of the global object. 这将创建一个全局变量,该变量不是全局对象的属性。 This is a new thing as of ES2015. 从ES2015开始这是新事物。

In specification terms, it creates an identifier binding on the declarative Environment Record for the global environment rather than the object Environment 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 object Environment Record) and another for all the new stuff ( let , const , and the functions created by class ) that don't go on the global object. 全局环境的独特之处在于它具有分开的环境记录,一个环境记录适用于全局对象上所有的旧内容( 对象环境记录),另一个适用于所有新的内容( letconst和由class创建的函数),不要继续使用全局对象。

The binding is created before any step-by-step code in its enclosing block is executed (in this case, before any global code runs), but it's not accessible in any way until the step-by-step execution reaches the let statement. 绑定是执行其封闭块中的任何分步代码之前创建的 (在这种情况下,在任何全局代码运行之前),但是在分步执行到达let语句之前,它无法以任何方式访问 Once execution reaches the let statement, the variable is accessible. 一旦执行到达let语句,就可以访问该变量。 (See "When let and const happen" below.) (请参见下面的“当letconst发生时”。)


#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. const就像let一样,除了必须提供一个初始化程序( = value部分),并且一旦创建常量就无法更改其值。 Under the covers, it's exactly like let but with a flag on the identifier binding saying its value cannot be changed. 在幕后,它就像let一样,但是在标识符绑定上带有一个标志,表明其值不能更改。 Using const does three things for you: 使用const可以为您做三件事:

  1. Makes it a parse-time error if you try to assign to the constant. 如果您尝试分配给常量,则使其成为解析时错误。
  2. Documents its unchanging nature for other programmers. 记录其对于其他程序员的不变性。
  3. 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 not doing 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. 如果您使用ES5的严格模式,则执行此操作(将其分配给不存在的变量)是错误的。 It's one of several reasons to use strict mode. 使用严格模式是多种原因之一。

And interestingly, again on IE8 and earlier, the property created not enumerable (doesn't show up in for..in statements). 有趣的是,再次在IE8和更早版本上,创建的属性不可枚举 (不会出现在for..in语句中)。 That's odd, particularly given #3 below. 这很奇怪,特别是在下面的#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). 这创建全局对象上的属性明确,使用window ,指的全局对象全局(在浏览器上;一些非浏览器环境具有等同的全局变量,诸如global上的NodeJS)。 As it's a normal property, you can delete it. 由于它是普通属性,因此可以将其删除。

This property is enumerable, 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 . 就像#3一样,除了我们通过this而不是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). 这在严格模式是行不通的,但是,因为在严格模式全局代码, this不具有全局对象(它的价值的参考undefined代替)。


Deleting properties 删除属性

What do I mean by "deleting" or "removing" a ? “删除”或“删除” a是什么意思? Exactly that: Removing the property (entirely) via the delete keyword: 正是这样:通过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. delete完全删除对象的属性。 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). 通过var间接将属性添加到window ,您将无法做到这一点, 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. 警告 :IE8再次出现(可能是更早的版本,而IE9-IE11处于损坏的“兼容性”模式):即使允许,也不允许您删除window对象的属性。 Worse, it throws an exception when you try ( try this experiment in IE8 and in other browsers). 更糟糕的是,尝试时会引发异常 (在IE8和其他浏览器中尝试此实验 )。 So when deleting from the window object, you have to be defensive: 因此,从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 only applies to the window object, and only (as far as I know) to IE8 and earlier (or IE9-IE11 in the broken "compatibility" mode). 适用于window对象,并且仅(据我所知)适用于IE8和更早的版本(或处于“兼容”模式的IE9-IE11)。 Other browsers are fine with deleting window properties, subject to the rules above. 其他浏览器可以删除window属性,但要遵守上述规则。


When var happens var发生时

The variables defined via the var statement are created before any step-by-step code in the execution context is run, and so the property exists well before the 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. 如您所见,符号foo在第一行之前定义,但符号bar未定义。 Where the var foo = "f"; 其中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. 这被称为“ var hoisting”,因为var foo部分已移动(“提升”)到范围的顶部,但是foo = "f"部分保留在其原始位置。 (See Poor misunderstood var on my anemic little blog.) (见可怜的误解var在我的贫血小博客。)


When let and const happen letconst发生时

let and const are different from var in a couple of ways. letconst在几个方面与var不同。 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 accessible until the let or const statement is reached. 与该问题相关的方式是,尽管它们定义的绑定是在任何分步代码运行之前创建的,但是直到到达letconst语句之后,才能访问该绑定。

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: letconstvar不同的其他两种方式与问题无关,它们是:

  1. var always applies to the entire execution context (throughout global code, or throughout function code in the function where it appears), but let and const apply only within the block where they appear. var始终应用于整个执行上下文(遍历全局代码,或出现在函数中的整个函数代码),但letconst仅适用于它们出现的内。 That is, var has function (or global) scope, but let and const have block scope. 也就是说, var具有函数(或全局)作用域,而letconst具有块作用域。

  2. Repeating var a in the same context is harmless, but if you have let a (or const a ), having another let a or a const a or a var a is a syntax error. 在相同的上下文中重复var a是无害的,但是如果let a (或const a ),则让另一个let aconst 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: 这是一个示例,演示letconst在该块中的任何代码运行之前立即在其块中生效,但是直到letconst语句才可访问:

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. window对象的属性变得非常混乱。 Whenever possible, strongly recommend not adding to the mess. 只要有可能,强烈建议不要增加混乱。 Instead, wrap up your symbols in a little package and export at most one symbol to the window object. 而是将符号包装在一个小包装中,并将最多一个符号导出到window对象。 (I frequently don't export any symbols 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对象。)您可以使用函数包含所有代码以包含符号,并且如果您愿意,该函数可以是匿名的:

(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 closures over that data (see: Closures are not complicated on my anemic little blog). 在作用域函数定义的,因为他们是在该数据关闭的作用域函数可以访问的变量中定义的函数(见: 瓶盖并不复杂在我贫血的小博客)。


#6楼

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. 这通常与全局变量相同。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值