关于javascript:var关键字的用途是什么?我应该在什么时候使用它(或者省略它)?

What is the purpose of the var keyword and when should I use it (or omit it)?

NOTE: This question was asked from the viewpoint of ECMAScript version 3 or 5. The answers might become outdated with the introduction of new features in the release of ECMAScript 6.

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

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

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

你什么时候用其中一个,为什么用它?


如果你在全球范围内,那么没有什么区别。读康克斯的答案来解释

如果您在函数中,那么var将创建一个局部变量,"no var"将查找作用域链,直到它找到该变量或到达全局作用域为止(此时它将创建该变量):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 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

1
var x; // Declare x


有区别。

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

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

现在,注意它不声明全局变量,而是创建一个全局属性。

这两者之间的区别是微妙的,可能会令人困惑,除非您了解变量声明也创建属性(仅在变量对象上),并且javascript中的每个属性(好的,ecmascript)都有一些描述其属性的标志-readonly、dontenum和dontDelete。

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

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

希望一切都有意义:)

[更新2010/12/16]

在ES5(ECMAScript 5;最近标准化,第五版语言)中,有一种所谓的"严格模式"——一种选择性语言模式,它稍微改变了未声明的作业的行为。在严格模式下,对未声明标识符的赋值是引用错误。其基本原理是捕获意外分配,防止创建不需要的全局属性。一些较新的浏览器已经开始滚动支持严格模式。例如,请参见my compat表。


说"本地"和"全球"的区别并不完全准确。

最好把它看成是"局部"和"最近"之间的区别。最近的肯定是全球性的,但情况并非总是如此。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/* 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语句包围,如下所示:

1
2
3
with (window) {
    //Your code
}

更多有关withMDN的信息

由于var在当前作用域中声明了一个变量,所以在窗口内部声明var与完全不声明该变量没有区别。

当您不直接在窗口中时(例如,在函数内部或在块内部),就会产生差异。

使用var可以隐藏同名的外部变量。通过这种方式,您可以模拟"private"变量,但这是另一个主题。

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

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

  • var声明了当前作用域中的变量
  • 全球范围是window
  • 不使用var在全局范围(window)中隐式声明var
  • 使用var在全局范围(窗口)中声明变量与省略变量相同。
  • 在不同于使用var的窗口的范围中声明变量与声明不使用var的变量不同。
  • 务必明确声明var,因为这是良好的做法


应该始终使用var关键字声明变量。为什么?良好的编码实践本身就足够有理由了,但是声明一个没有var关键字的变量意味着它是在全局范围内声明的(类似这样的变量称为"隐含的"全局)。Douglas Crockford建议不要使用隐含的全局变量,根据Apple javascript编码指南:

Any variable created without the var
keyword is created at the global scope
and is not garbage collected when the
function returns (because it doesn’t
go out of scope), presenting the
opportunity for a memory leak.

因此,简而言之,总是使用var关键字声明变量。


下面是一个很好的例子,说明如何避免使用var声明局部变量:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
one();

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

function two()
{
    i = 1;
}

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


我想说在大多数情况下最好使用var

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

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

更多信息,你可以在谷歌搜索"范围链javascript"。


不带var—全局变量。

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

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

另一个区别例如

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

虽然

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


使用var总是一个好主意,可以防止变量混淆全局范围,避免变量相互冲突,导致不必要的重写。


不要使用var

var是pre-es6方法来声明变量。我们现在在未来,您应该这样编码。

使用constlet

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

对于希望重新分配的变量,应使用let。这包括在for循环中。如果在初始化之后编写varName =,请使用let

正如大多数其他语言所预期的那样,这两种语言都具有块级作用域。


这是我为您编写的用于理解此概念的示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var foo = 5;
bar = 2;    
fooba = 3;

// Execute an anonymous function
(function() {    
    bar = 100;             //overwrites global scope bar
    var foo = 4;           //a new foo variable is created in this' function's scope
    var fooba = 900;       //same as above
    document.write(foo);   //prints 4
    document.write(bar);   //prints 100
    document.write(fooba); //prints 900
})();

document.write('<br/>');
document.write('<br/>');
document.write(foo);       //prints 5
document.write(bar);       //prints 100
document.write(fooba);     //prints 3


@Chris S给出了一个很好的例子,展示了var和no var之间的实际区别(和危险)。这是另一个,我发现这个特别危险,因为这个差异只在异步环境中可见,所以在测试过程中很容易被忽略。

正如您所期望的,下面的代码片段将输出["text"]

1
2
3
4
5
6
7
function var_fun() {
  let array = []
  array.push('text')
  return array
}

console.log(var_fun())

下面的代码片段也是如此(注意在array之前缺少的let):

1
2
3
4
5
6
7
function var_fun() {
  array = []
  array.push('text')
  return array
}

console.log(var_fun())

异步执行数据操作仍然会产生与单个执行器相同的结果:

1
2
3
4
5
6
7
8
9
function var_fun() {
  array = [];
  return new Promise(resolve => resolve()).then(() => {
    array.push('text')
    return array
  })
}

var_fun().then(result => {console.log(result)})

但在多个方面表现不同:

1
2
3
4
5
6
7
8
9
10
11
function var_fun() {
  array = [];
  return new Promise(resolve => resolve()).then(() => {
    array.push('text')
    return array
  })
}

[1,2,3].forEach(i => {
  var_fun().then(result => {console.log(result)})
})

但是,使用let:

1
2
3
4
5
6
7
8
9
10
11
function var_fun() {
  let array = [];
  return new Promise(resolve => resolve()).then(() => {
    array.push('text')
    return array
  })
}

[1,2,3].forEach(i => {
  var_fun().then(result => {console.log(result)})
})


在代码中,如果使用变量而不使用var,则会自动将var var_名称放在全局范围中,例如:

1
2
3
4
5
6
someFunction() {
    var a = some_value; /*a has local scope and it cannot be accessed when this
    function is not active*/

    b = a; /*here it places"var b" at top of script i.e. gives b global scope or
    uses already defined global variable b */

}

如果不使用"var",变量只能在设置值时定义。例如:

1
my_var;

无法在全局范围或任何其他范围内工作。它的值应该是:

1
my_var ="value";

另一方面,你可以定义一个可用的类;

1
var my_var;

它的值是undefined(它的值不是null,有趣的是它不等于null)。


当一些人试图了解这一点时,这就是我所看到的。对于初学者来说,上面的例子可能有点过于复杂。

如果运行此代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var local = true;
var global = true;


function test(){
  var local = false;
  var global = false;
  console.log(local)
  console.log(global)
}

test();

console.log(local);
console.log(global);

输出将读取为:假、假、真、真

因为它认为函数中的变量与它外部的变量是分开的,所以术语局部变量,这是因为我们在赋值中使用了var。如果去掉函数中的var,那么它现在的读数如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var local = true;
var global = true;


function test(){
  local = false;
  global = false;
  console.log(local)
  console.log(global)
}

test();

console.log(local);
console.log(global);

输出为假、假、假、假

这是因为它不在本地范围或函数中创建新的变量,而只是使用全局变量并将其重新分配为false。


我看到,当声明变量时,无论有无var,函数内部还是外部,人们都会感到困惑。下面是一个深入的例子,将引导您完成以下步骤:

请参阅下面在jsfiddle中的脚本。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
a = 1;// Defined outside the function without var
var b = 1;// Defined outside the function with var
alert("Starting outside of all functions...
 
 a, b defined but c, d not defined yet:
 a:"
+ a +"
 b:"
+ b +"
 
 (If I try to show the value of the undefined c or d, console.log would throw 'Uncaught ReferenceError: c is not defined' error and script would stop running!)"
);

function testVar1(){
    c = 1;// Defined inside the function without var
    var d = 1;// Defined inside the function with var
    alert("Now inside the 1. function:
 a:"
+ a +"
 b:"
+ b +"
 c:"
+ c +"
 d:"
+ d);

    a = a + 5;
    b = b + 5;
    c = c + 5;
    d = d + 5;

    alert("After added values inside the 1. function:
 a:"
+ a +"
 b:"
+ b +"
 c:"
+ c +"
 d:"
+ d);
};


testVar1();
alert("Run the 1. function again...");
testVar1();

function testVar2(){
    var d = 1;// Defined inside the function with var
    alert("Now inside the 2. function:
 a:"
+ a +"
 b:"
+ b +"
 c:"
+ c +"
 d:"
+ d);

    a = a + 5;
    b = b + 5;
    c = c + 5;
    d = d + 5;

    alert("After added values inside the 2. function:
 a:"
+ a +"
 b:"
+ b +"
 c:"
+ c +"
 d:"
+ d);
};

testVar2();

alert("Now outside of all functions...
 
 Final Values:
 a:"
+ a +"
 b:"
+ b +"
 c:"
+ c +"
 You will not be able to see d here because then the value is requested, console.log would throw error 'Uncaught ReferenceError: d is not defined' and script would stop.
"
);
alert("**************
 Conclusion
 **************
 
 1. No matter declared with or without var (like a, b) if they get their value outside the function, they will preserve their value and also any other values that are added inside various functions through the script are preserved.
 2. If the variable is declared without var inside a function (like c), it will act like the previous rule, it will preserve its value across all functions from now on. Either it got its first value in function testVar1() it still preserves the value and get additional value in function testVar2()
 3. If the variable is declared with var inside a function only (like d in testVar1 or testVar2) it will will be undefined whenever the function ends. So it will be temporary variable in a function."
);
alert("Now check console.log for the error when value d is requested next:");
alert(d);

Conclusion

  • No matter declared with or without var (like a, b) if they get their value outside the function, they will preserve their value and also any other values that are added inside various functions through the script are preserved.
  • If the variable is declared without var inside a function (like c), it will act like the previous rule, it will preserve its value across all functions from now on. Either it got its first value in function testVar1() it still preserves the value and get additional value in function testVar2()
  • If the variable is declared with var inside a function only (like d in testVar1 or testVar2) it will will be undefined whenever the function ends. So it will be temporary variable in a function.

  • 您应该使用var关键字,除非您希望将变量附加到浏览器中的window对象。这是一个链接,解释了使用和wihtout var关键字的范围界定和本地范围界定之间的区别。

    当不使用var关键字定义变量时,它看起来像是一个简单的"赋值"操作。

    当该值在javascript中分配给变量时,解释器首先尝试在与赋值相同的上下文/范围中查找"变量声明"。当解释器执行dummyVariable = 20时,它会在函数开头查找dummyvariable的声明。(因为所有变量声明都被javascript解释器移动到上下文的开头,这称为提升)

    您可能还想看看JavaScript中的提升