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

1664

注意:该问题是从 ECMAScript 版本 3 或 5 的视角提出的。随着 ECMAScript 6 发布新功能,答案可能会过时。

var 关键字在 JavaScript 中起到了什么作用?与之相比,letconst 又有什么区别?

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

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

你什么时候会使用其中之一,为什么/它有什么作用?


6
在链接变量声明时,逗号后面加换行符是否会影响行为?var x = 1, y = 2, [return]z = 3; - Alfabravo
6
如果不使用"var",你选择的变量名称可能会是之前定义的全局变量,这会让你处于暴露的风险中。在这里您可以查看我的悲痛历程:http://stackoverflow.com/questions/16704014/why-do-chrome-and-firefox-handle-javascript-variable-set-inside-jquery-ajax-ca - Scott C Wilson
7
@Ray Toal的瓜卡博客文章(绝对值得一读)已经迁移到http://blog.safeshepherd.com/23/how-one-missing-var-ruined-our-launch/。 - Hephaestus
2
使用 constlet 吧!var 不是现代的 JS。 - Gibolt
3
@Gibolt 但是看一下问题的日期,召唤一个2009年的问题有点不公平。尽管如此,对于可维护性来说,仍然在当前日期是有效的,因为有很多不是“现代JS”的代码存在。 - Andre Figueiredo
显示剩余3条评论
19个回答

11

没有使用 var - 全局变量。

强烈建议始终使用 var 语句,因为在本地上下文中初始化全局变量是有害的。但是,如果您需要这种不好的技巧,您应该在页面开头写注释:

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

6

这是我为了让您理解这个概念而编写的示例代码:

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

3
这个函数绝不是“匿名”的。事实上,它的命名显眼到极致了。 - Ingo Bürk
1
感谢您根据Ingo Bürk的评论编辑了您的答案,使“匿名函数”真正成为匿名。 - Dave Burton

6

@Chris S举了一个很好的例子,展示了var和没有var之间实际的差异(和危险)。这里有另一个例子,我认为这个例子特别危险,因为它们之间的区别只在异步环境中可见,所以在测试期间很容易忽略。

正如你所预期的那样,以下片段输出["text"]

function var_fun() {
  let array = []
  array.push('text')
  return array
}

console.log(var_fun())

因此,以下代码片段(请注意array前缺少的 let):

function var_fun() {
  array = []
  array.push('text')
  return array
}

console.log(var_fun())

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

function var_fun() {
  array = [];
  return new Promise(resolve => resolve()).then(() => {
    array.push('text')
    return array
  })
}

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

但是在有多个时,其行为会有所不同:

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:

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)})
})


感谢@thisismydesign的示例!关于最后两个示例,为什么倒数第二个示例记录了一个由三个元素组成的数组,其中文本被写了三次,而最终的示例仅在数组中每个元素内部记录了一次“text”?(我理解最后一个示例将“array”声明为变量,因此处于局部范围,而倒数第二个示例省略了这一点,使“array”成为隐含的全局范围的一部分。)但是,这会如何影响输出?这是因为forEach“i”遍历函数和所有全局变量吗? - Brad Ahrens

5
作为一个试图学习的人,我这样理解。上面的例子可能对于初学者来说有点过于复杂。
如果您运行这段代码:
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);

输出结果为:false,false,true,true。

这是因为它将函数内的变量视为与外部变量分开的变量,因此称为局部变量,这是因为我们在赋值时使用了 var。如果您从函数中去掉 var,使其像这样:

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,false,false,false。这是因为它没有在本地作用域或函数中创建新变量,而是直接使用全局变量并将其重新赋值为false。

5
我发现很多人在声明变量时会对是否使用var以及是在函数内部还是外部感到困惑。以下是一个深入的例子,将带你了解这些步骤:

在jsfiddle上查看下面的脚本示例

a = 1;// Defined outside the function without var
var b = 1;// Defined outside the function with var
alert("Starting outside of all functions... \n \n a, b defined but c, d not defined yet: \n a:" + a + "\n b:" + b + "\n \n (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: \n a:" + a + "\n b:" + b + "\n c:" + c + "\n d:" + d);

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

    alert("After added values inside the 1. function: \n a:" + a + "\n b:" + b + "\n c:" + c + "\n 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: \n a:" + a + "\n b:" + b + "\n c:" + c + "\n d:" + d);

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

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

testVar2();

alert("Now outside of all functions... \n \n Final Values: \n a:" + a + "\n b:" + b + "\n c:" + c + "\n 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. \n ");
alert("**************\n Conclusion \n ************** \n \n 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.\n 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() \n 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);

结论

  1. 无论是声明带有还是不带有var(如a,b),如果它们在函数外获取其值,则它们将保留其值,并且通过脚本添加到各种函数中的任何其他值也将被保留。
  2. 如果变量在函数内部未使用var声明(如c),它将像上一个规则一样,将保留其值并跨所有函数。即使它在函数testVar1()中首次获取了其值,它仍会保留该值并在函数testVar2()中获取其他值。
  3. 如果变量仅在函数内部使用var声明(如testVar1或testVar2中的d),则在函数结束时它将为未定义。因此,它将是函数中的临时变量。

感谢您抽出时间创建一个示例来演示这个主题。上面的代码缺少下面的部分,所以您可能需要编辑您的答案: a = 1;// 在函数外部定义而没有var var b = 1;// 在函数外部定义并使用了var alert("在所有函数之外开始... \n \n a, b已定义,但c, d尚未定义:\n a:" + a + "\n b:" + b + "\n \n (如果我尝试显示未定义的c或d的值,console.log将抛出'Uncaught ReferenceError: c is not defined'错误,脚本将停止运行!)"); - Sankofa

4

如果您在代码中使用变量却没有使用var,则会自动将变量名放置在全局作用域中,例如:

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

4
除了作用域问题之外,有些人还提到变量提升hoisting,但没有人给出例子。这里有一个全局作用域的例子:

console.log(noErrorCase);
var noErrorCase = "you will reach that point";

console.log(runTimeError);
runTimeError = "you won't reach that point";


3

如果您不想将变量附加到浏览器窗口对象上,应使用var关键字。这是一个解释作用域和使用和不使用var关键字的全局作用域和局部作用域差异的链接。

当变量在JavaScript中定义时没有使用var关键字时,它看起来像是一个简单的“赋值”操作。

当值被分配给JavaScript变量时,解释器首先尝试在与分配相同的上下文/作用域中查找“变量声明”。当解释器执行dummyVariable = 20时,它会在函数开头查找dummyVariable的声明。 (由于JavaScript解释器将所有变量声明移至上下文的开头,这被称为提升)

您还可以查看JavaScript中的提升


3

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

my_var;

无法在全局作用域任何其他作用域中工作。它应该具有像这样的值:

my_var = "value";

另一方面,您可以像这样定义一个变量:

var my_var;

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


1
my_var; 实际上是一个有效的表达式语句。 - lexicore
如果变量在之前被定义了,那么这是一个有效的语句。否则它会抛出一个错误“...未定义”。 - umut
3
无论变量之前是否定义,这个陈述都是正确的 :) 一个有效的语句可能会抛出错误,但这并不使得该语句无效。 - lexicore
我对此感到困惑。什么是有效的语句?你能给我一个无效语句的例子吗? - umut
我必须道歉 - 最近太多的ECMAScript语法了。my_var;是一个有效的表达式语句/my_var;将是一个无效的语句。但正如我所说,这是语法细节,我很抱歉,我的评论实际上不合适。 - lexicore

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接