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

注意 :从 ECMAScript 版本 3 或 5 的角度提出了此问题。随着 ECMAScript 6 版本中引入新功能,答案可能会过时。

JavaScript 中var关键字的功能到底是什么,它们之间有什么区别

var someNumber = 2;
var someFunction = function() { doSomething; }
var someObject = { }
var someObject.someProperty = 5;

someNumber = 2;
someFunction = function() { doSomething; }
someObject = { }
someObject.someProperty = 5;

您什么时候会使用其中一个?为什么 / 会做什么?

答案

如果您位于全球范围内,则没有太大区别。阅读Kangax 的答案以获取解释

如果您在函数中,则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

有区别

var x = 1在当前作用域(即执行上下文)中声明变量 x 。如果声明出现在函数中 - 声明局部变量;如果在全局范围内,则声明一个全局变量。

另一方面, x = 1仅仅是一个属性分配。它首先尝试根据范围链解析x 。如果在范围链中的任何地方找到它,它将执行分配;否则,它将执行分配。如果找不到x ,则只有在全局对象 (范围链中的顶级对象) 上创建x属性

现在,请注意,它没有声明全局变量,而是创建了全局属性。

除非您了解变量声明还创建属性 (仅在变量对象上),并且 Javascript 中的每个属性(以及 ECMAScript)都有某些描述其属性的标志,否则两者之间的区别可能是令人困惑的,并且可能会造成混淆:ReadOnly,DontEnum 和不要删除。

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

但这当然只是理论, 实际上 ,由于实现中的各种错误(例如来自 IE 的错误), 两者之间甚至存在更多差异

希望这一切有意义:)


[2010 年 12 月 16 日更新]

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

说这是 “ 本地”和 “ 全球 ” 之间的差异并不完全准确。

最好将其视为 “ 本地”和 “ 最近 ” 之间的差异。最接近的肯定是全局的,但情况并非总是如此。

/* 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;
    }
}

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

with (window) {
    //Your code
}

关于更多信息with - MDN

由于var 在当前作用域中声明了一个变量,因此在窗口内部声明var与根本不声明它之间没有区别。

当您不直接位于窗口内部(例如,在函数内部或在块内部)时,就会出现区别。

使用var可以隐藏具有相同名称的外部变量。这样,您可以模拟 “私有” 变量,但这是另一个主题。

一条经验法则是始终使用var ,否则会冒引入细微错误的风险。

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

  • var 在当前范围内声明一个变量
  • 全局范围是window
  • 不使用var在全局范围内(窗口)隐式声明var
  • 使用var在全局范围(窗口)中声明变量与省略变量相同。
  • 声明中使用的窗口不同范围的变量var 是不一样的东西声明一个变量没有var
  • 始终明确声明var因为这是一种很好的做法

始终使用var关键字声明变量。为什么?良好的编码习惯本身就足够了,但是省略它意味着在全局范围内声明它(像这样的变量称为 “隐式” 全局)。道格拉斯 · 克罗克福德(Douglas Crockford) 建议不要使用隐式全局变量 ,并且根据Apple JavaScript 编码准则

没有使用var关键字创建的任何变量都在全局范围内创建,并且在函数返回时不会被垃圾回收(因为它不会超出范围),这会导致内存泄漏。

这是一个很好的示例,说明了如何通过不使用var声明局部变量而陷入困境:

<script>
one();

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

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

i在循环的每次迭代中都会重置,因为它不是在for循环中本地声明,而是在全局中声明),最终导致无限循环

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

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

如果不使用var声明变量,则该变量将处于全局范围内。

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

不要使用var

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

使用constlet

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

let应该用于期望重新分配的任何变量。这包括在 for 循环中。如果您曾经在初始化之外编写varName = ,请使用let

正如大多数其他语言所期望的那样,它们都具有块级作用域。

没有var全局变量。

强烈建议始终使用var语句,因为在局部上下文中初始化全局变量 - 是邪恶的。但是,如果您需要这个肮脏的把戏,则应在页面开头写评论:

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

另一个区别,例如

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

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