题 var关键字的目的是什么?我何时应该使用它(或省略它)?


注意:这个问题是从ECMAScript第3版或第5版的角度提出来的。在ECMAScript 6发布中引入新功能后,答案可能会过时。


1390
2017-09-24 08:54


起源


总是使用var!即使在全球范围内,否则您可能会遇到IE问题(至少版本6)。我是根据自己的经验告诉你的。 - Jamol
链接var声明时,在逗号后面添加换行符会影响行为吗? var x = 1,y = 2,[return] z = 3; - Alfabravo
如果您选择的变量名恰好是先前定义的全局变量,则无法使用“var”也会使您暴露。看看我的悲伤之旅: stackoverflow.com/questions/16704014/... - Scott C Wilson
@Ray Toal的meloncard博客文章(绝对值得一读)已经转移到了 blog.safeshepherd.com/23/how-one-missing-var-ruined-our-launch - Hephaestus
我从未想过一首诗能激发我对程序化问题的考虑 - Félix Gagnon-Grenier


答案:


如果你处于全球范围,那么没有区别。

如果你在一个功能那么 var 将创建一个局部变量,“no var”将查找范围链,直到它找到变量或命中全局范围(此时它将创建它):

// These are both globals
var foo = 1;
bar = 2;

function()
{
    var foo = 1; // Local
    bar = 2;     // Global

    // Execute an anonymous function
    (function()
    {
        var wibble = 1; // Local
        foo = 2; // Inherits from scope above (creating a closure)
        moo = 3; // Global
    }())
}

如果你没有做任务,那么你需要使用 var

var x; // Declare x

1255
2017-09-24 08:55



“没有太大区别”==“没有差异”? - Alex
嗯,实际上是的,有区别:)这个差异是否重要是另一个问题。请进一步查看我的答案: stackoverflow.com/questions/1470488/... - kangax
我认为这可能是亚历克斯的观点,这就是为什么他用“等于”运算符写它的原因! - James Bedford
这就像用铁轨枪射击自己......忘了在一个变量之前放一个'var',最后修改一个变量 某处 在范围链中...尝试说服Java / C / Python /等。开发人员认为JavaScript是值得的。哈!相比之下,C / C ++陷阱看起来很不错。想象一下,必须调试JavaScript ......当然,有些人会这样做。用JavaScript编写的代码很多(而不是简单的代码,请注意)... - Albus Dumbledore
如果你处于全球范围,那么没有区别。 >>存在差异,将在下面的答案中解释 - AngularInDepth.com


有区别

var x = 1  声明变量  x 在当前范围(也称为执行上下文)。如果声明出现在函数中 - 声明了局部变量;如果它在全局范围内 - 声明了一个全局变量。

x = 1另一方面,仅仅是财产分配。它首先尝试解决 x 反对范围链。如果它在该范围链中的任何位置找到它,它将执行赋值;如果找不到 x,只有这样 它创建 x 全局对象上的属性 (它是作用域链中的顶级对象)。

现在,请注意它没有声明全局变量,它会创建一个全局属性。

除非你理解,否则两者之间的差异是微妙的,可能会令人困惑 变量声明也创建属性 (仅限于变量对象)并且Javascript(嗯,ECMAScript)中的每个属性都有某些描述其属性的标志 - ReadOnly,DontEnum和DontDelete。

由于变量声明使用DontDelete标志创建属性,因此之间存在差异 var x = 1 和 x = 1 (在全局范围内执行时)是前一个 - 变量声明 - 创建DontDelete'able属性,后者不创建。因此,可以从全局对象中删除通过此隐式赋值创建的属性,并且不能删除前一个 - 通过变量声明创建的属性。

但这当然是理论,而且 在实践中,两者之间存在更多差异,由于实现中的各种错误(例如来自IE的错误)。

希望这一切都有道理:)


[更新2010/12/16]

在ES5(ECMAScript 5;最近标准化,第5版语言)中,有一种所谓的“严格模式” - 一种选择加入语言模式,它略微改变了未声明的作业的行为。在严格模式下,分配给未声明的标识符是a 引发ReferenceError。这样做的理由是捕获意外分配,防止产生不希望的全局属性。一些较新的浏览器已经开始支持严格模式。例如,参见 我的compat表


697
2017-09-24 13:38



如果我没记错的话,我想我曾经找到了一种能够做到的方法 delete 一个var声明的变量 eval 黑客攻击。如果我记得我将在这里发布的确切技巧。 - Tower
@Mageek他可能正在处理可删除的eval声明的变量。我写了一篇 关于此的博客文章 一旦。 - kangax
有点偏离主题,但在此提及以供参考。 “let”与“var”非常相似,并且在Mozilla中受支持。主要区别在于var变量的范围是整个封闭函数,其中“let”仅限于其块 - mac
@kangax如果Alex的例子的最后两行是混合的: var someObject = {} 和 someObject.someProperty = 5?将 someProperty 变得全球化,而它是一个属性的对象仍然是本地的? - snapfractalpop
@kangax称之为的规范名称 DontDelete 国旗是 可配置的(= false),你可以阅读有关这方面的内容 Object.defineProperty 和 Object.getOwnPropertyDescriptor - Paul S.


说它是“之间的区别”本地 和 全球“并不完全准确。

将其视为“两者之间的区别”可能更好。本地 和 最近的“。最接近的肯定是全球性的,但情况并非总是如此。

/* global scope */
var local = true;
var global = true;

function outer() {
    /* local scope */
    var local = true;
    var global = false;

    /* nearest scope = outer */
    local = !global;

    function inner() {
        /* nearest scope = outer */
        local = false;
        global = false;

        /* nearest scope = undefined */
        /* defaults to defining a global */
        public = global;
    }
}

130
2017-09-24 09:50



不是最近的范围 outer 在哪里定义 var global = false;? - Snekse
@Snekse:当声明<code> var global = false; </ code>时,'nearest'不适用。在该声明中,'global'被置于outer()的范围内,因为'var'在声明中使用。因为在内部()中没有使用'var',所以它将更改下一级别的值,即outer()。 - Mitch
我想知道如果你改变那条线,你的评论是否会改变 var global = local; 在这种情况下,本地的近似范围将是主动定义的“本地”外部范围。虽然如果你改变同一行会很奇怪 var global = global 在这种情况下,搜索值的最近范围 global 将在全球窗口范围内达到一个水平。 - Snekse


当Javascript在浏览器中执行时,所有代码都被with语句包围,如下所示:

with (window) {
    //Your code
}

更多信息 with  - MDN

以来 var 声明一个变量 在目前的范围内 ,宣告之间没有区别 var  在窗口内 并没有宣布它。

当你没有直接进入窗户时,就会产生差异,例如:在函数内部或块内部。

运用 var 允许您隐藏具有相同名称的外部变量。通过这种方式,您可以模拟“私有”变量,但这是另一个主题。

经验法则是始终使用 var,因为否则你冒着引入细微错误的风险。

编辑: 在收到批评后,我想强调以下几点:

  • var 声明一个变量 在目前的范围内
  • 全球范围是 window
  • 不使用 var 含蓄地宣称 var 在全球范围内(窗口)
  • 使用在全局范围(窗口)中声明变量 var 与省略它是一样的。
  • 声明范围中的变量与窗口使用不同 var  是不一样的 如没有声明变量 var
  • 总是声明 var 明确是因为这是一种很好的做法

76
2017-09-24 09:17



我没有向你投票,但范围可能比窗口更好。你的整个解释有点迟钝。 - Robert Harvey♦
我只是用它的名字来调用它,你想把它称为“全局范围”,没关系,但是按照惯例,客户端是窗口对象,这是范围链的最后一个元素,为什么你可以调用每个函数和窗口中的每个对象都没有写“窗口”。 - kentaromiura
+1这是一个非常好的解释 - 我之前没有听到过var / no var问题框架(没有双关语)。 - doug
大多数答案都被弃用了 let 在ES6中。 - Evan Carroll
@EvanCarroll这个答案在技术上也是不正确的,因为省略var不会声明任何变量,而是在全局对象上创建一个可删除的属性,除了ES5“use strict”模式,大多数答案显然是不正确的,也让我没有甚至在这个答案中也考虑过,因为在问题的时候没有任何关于javascript版本(昨天添加)的提法,这意味着参考标准(当时)是ECMA 262第3版。 - kentaromiura


你应该 总是 使用 var 用于声明变量的关键字。为什么?良好的编码实践本身应该是一个理由,但是在没有的情况下声明一个变量 var 关键字表示它在。中声明 全球 范围(像这样的变量称为“隐含”全局)。道格拉斯克罗克福德 建议不要使用隐含的全局变量,并根据 Apple JavaScript编码指南

没有创建的任何变量 var   关键字在全局范围内创建   并且不是垃圾收集的时候   函数返回(因为它没有   超出范围),提出   内存泄漏的机会。

所以,简而言之,总是使用the声明变量 var 关键词。


37
2017-09-24 09:52



“良好的编码实践”本身不应该是充分理由。这相当于“互联网上的一些人说这是我的代码看起来的样子”。这比“老师说的”更有效,除非至少模糊地理解规则背后的原因。 - cHao
@cHao我想 good coding practice 如果这是一个推荐的最佳实践,这总是充分的理由,这是由几个Javascript作者。 - Chris S
@ChrisS:不,“良好的编码实践”本身并不是理由。该 原因 它被认为是好的做法才是最重要的。除非那些作者告诉你他们为什么推荐它,否则他们的推荐应该没有任何重量。如果您不同意原因,那么您可以自由地认为这是一个糟糕的建议。如果你在没有问过为什么的情况下遵循它,那就是货运崇拜的开始。 - cHao


这是一个很好的例子,说明如何在不声明局部变量的情况下陷入困境 var

<script>
one();

function one()
{
    for (i = 0;i < 10;i++)
    {
        two();
        alert(i);
    }
}

function two()
{
    i = 1;
}
</script>

i 在循环的每次迭代时重置,因为它没有在本地声明 for 循环但全局)最终导致无限循环


27
2017-09-24 09:31



哎呀!我可以想象这个错字造成的所有错误。 - BonsaiOak
我很好奇,为什么你把我作为一个参数传递给两个()? (for循环内部)是多余的? - kalin
在one()函数中封装的two()函数中忽略该参数,因为函数two()是在没有参数的情况下定义的。你是完全正确的,因为它不起作用,所以不需要它。 - KK.


我会说最好用 var 在大多数情况下。

局部变量总是比全局范围内的变量快。

如果你不使用 var 要声明一个变量,该变量将在全局范围内。

有关详细信息,您可以在Google中搜索“范围链JavaScript”。


12
2017-09-24 09:02



如果使用var关键字声明变量,它将在运行时创建,所以它不应该慢吗?因为其他的是在解析时创建的。 - Ryu Kaplan
@RyuKaplan - 嘿,是真的吗?我尝试使用谷歌搜索,无法获得有关该主题的任何信息!你有这个断言的源权限吗?谢谢 - mike rodent
@RyuKaplan解析/编译与实际运行代码不同。 - gcampbell


另一个区别 例如

var a = a || [] ; // works 

a = a || [] ; // a is undefined error.

8
2017-08-09 22:11



你可以解释一下为什么它在用'var'定义的变量和用var定义的变量的情况下有效吗?如果是,则在评估分配右侧之前创建变量 var? - matt
@Lucek因为 var a 被提升到作用域的顶部并设置为null,它声明但不初始化变量,然后在赋值中你有一个未定义的null变量的引用,该变量的计算结果为false,并将赋值设置为 []。在后者,您有一个属性的任务 a 属性 a。您可以分配给不存在的属性 - 在分配时创建它,但是如果没有获取,则无法从不存在的属性中读取 ReferenceError 扔给你。 - Evan Carroll
@EvanCarroll:它被提升到范围的顶部并被设置为undefined而不是null。 - mithunsatheesh


运用 var 总是一个好主意,以防止变量混乱全局范围和变量相互冲突,导致不必要的覆盖。


7
2018-04-04 23:14





没有 var  - 全局变量。

强烈推荐 总是 使用 var 声明,因为在本地环境中的init全局变量 - 是邪恶的。但是,如果你需要这个肮脏的技巧,你应该在页面开头写评论:

/* global: varname1, varname2... */

7
2017-09-24 09:04





不要用 var

var 是ES6之前声明变量的方法。我们现在 在将来,你应该这样编码。

使用 const 和 let

const 应该用于95%的病例。它使得变量引用无法更改,因此数组,对象和DOM节点属性可以更改并且应该可能更改 const

let 应该用于任何期望被重新分配的变量。这包括在for循环中。如果你写过 varName = 超出初始化,使用 let

两者都具有块级别范围,正如大多数其他语言所预期的那样。


4
2017-08-15 18:49