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

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

var关键字在JavaScript中的作用到底是什么,它们之间的区别是什么

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

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

?

你什么时候会使用任何一个,为什么/它做什么?

326498 次浏览

如果你在全局范围内,那么没有太大的区别。阅读康加克斯的答案以获得解释

如果你在一个函数中,那么#0将创建一个局部变量,“no var”将查找作用域链,直到找到变量或命中全局作用域(此时它将创建它):

// These are both globalsvar foo = 1;bar = 2;
function(){var foo = 1; // Localbar = 2;     // Global
// Execute an anonymous function(function(){var wibble = 1; // Localfoo = 2; // Inherits from scope above (creating a closure)moo = 3; // Global}())}

如果你不做赋值,那么你需要使用var

var x; // Declare x

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

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

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

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

没有var-全局变量。

强烈建议一直都是使用var语句,因为在本地上下文中初始化全局变量-是邪恶的。但是,如果你需要这个肮脏的技巧,你应该在页面开始时写注释:

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

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

with (window) {//Your code}

更多信息#0-MDN

由于var声明了一个变量在当前范围,因此声明var内窗和根本不声明它之间没有区别。

当你不直接在窗口内时,差异就来了,例如在函数内或块内。

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

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

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

  • var声明了一个变量在当前范围
  • 全局范围是window
  • 不使用var隐式声明全局范围(窗口)中的var
  • 使用var在全局作用域(窗口)中声明变量与省略它相同。
  • 使用var不是一回事在不同于windows的范围内声明变量,就像声明没有var的变量一样
  • 始终明确声明var,因为这是良好的做法

这里有一个很好的例子,说明如何避免使用var声明局部变量:

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

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

说这是“当地全球”之间的区别并不完全准确。

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

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

总是使用var关键字来声明变量。为什么?良好的编码实践本身就应该是一个足够的理由,但是省略它意味着它被声明在全球范围内(像这样的变量称为“隐含”全局)。Douglas Crockford建议永远不要使用隐含全局变量,根据Apple JavaScript编码指南

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

这是有区别的

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

另一方面,x = 1仅仅是一个属性赋值。它首先尝试根据作用域链解析x。如果它在该作用域链的任何地方找到它,它将执行赋值;如果它没有找到x,那么只有它在全局对象上创建#1属性(它是作用域链中的顶级对象)。

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

两者之间的区别很微妙,可能会令人困惑,除非您了解变量声明也创建属性(仅在变量对象上)和Javascript中的每个属性(嗯,ECMAScript)都有某些描述其属性的标志-ReadOnly,DontEnum和DontDelete。

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

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

希望一切都有意义:)


[更新2010/12/16]

在ES5(ECMAScript 5;最近标准化,该语言的第五版)中,有一个所谓的“严格模式”——一种选择加入的语言模式,它稍微改变了未声明赋值的行为。在严格模式下,对未声明标识符的赋值是引用错误。这样做的理由是捕获意外赋值,防止创建不想要的全局属性。一些较新的浏览器已经开始滚动支持严格模式。例如,请参见我的同桌

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

另一个区别e. g

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

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

在代码中,如果您使用变量而不使用var,则会自动将varvar_name放置在全局范围内,例如:

someFunction() {var a = some_value; /*a has local scope and it cannot be accessed when thisfunction is not active*/b = a; /*here it places "var b" at top of script i.e. gives b global scope oruses already defined global variable b */}

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

var foo = 5;bar = 2;fooba = 3;
// Execute an anonymous function(function() {bar = 100;             //overwrites global scope barvar foo = 4;           //a new foo variable is created in this' function's scopevar fooba = 900;       //same as abovedocument.write(foo);   //prints 4document.write(bar);   //prints 100document.write(fooba); //prints 900})();
document.write('<br/>');document.write('<br/>');document.write(foo);       //prints 5document.write(bar);       //prints 100document.write(fooba);     //prints 3

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

my_var;

不能在全球范围任何其他范围中工作。它的值应该是:

my_var = "value";

另一方面,你可以定义一个vaiable like;

var my_var;

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

作为一个试图学习这个的人,我是这样看的。上面的例子对于初学者来说可能有点过于复杂。

如果您运行此代码:

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。

我看到人们在声明带有或不带有var以及函数内部或外部的变量时感到困惑。这是一个深入的示例,将引导您完成这些步骤:

在jsfiddle中查看下面的脚本

a = 1;// Defined outside the function without varvar b = 1;// Defined outside the function with varalert("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 varvar d = 1;// Defined inside the function with varalert("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 varalert("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),则每当函数结束时它都将是未定义的。所以它将是函数中的临时变量。

您应该使用var关键字,除非您打算将变量附加到浏览器中的窗口对象。这里有一个链接,解释了作用域以及gLocal作用域和使用和wihtout var关键字的本地作用域之间的区别。

当变量在不使用var关键字的情况下被定义时,它看起来像是一个简单的“赋值”操作。

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

你可能还想看看javascript中的提升

不要使用var

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

使用constlet

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

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

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

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

正如您所期望的,以下代码段输出["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)})})

除了作用域的问题,有些人也提到了吊装,但没有人举一个例子。这是一个全局范围的例子:

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

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