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

JavaScript中var关键字的功能是什么

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

and

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更好。

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

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

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


没有var-全局变量。

强烈建议始终使用var语句,因为本地上下文中的init全局变量是有害的。但,若你们需要这个肮脏的伎俩,你们应该在页面的开头写下评论:

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

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

with (window) {
    //Your code
}

有关-MDN的更多信息

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

不同的是,当你不直接在窗口内时,例如在函数内或块内。

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

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

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

var声明当前范围中的变量全局范围是窗口不使用var在全局范围(窗口)中隐式声明var使用var在全局范围(窗口)中声明变量与省略变量相同。使用var在不同于window的作用域中声明变量与不使用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编码指南:

在没有变量的情况下创建的任何变量关键字是在全局范围内创建的并且当函数返回(因为它没有超出范围),呈现内存泄漏的机会。


这是不同的。

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

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

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

这两者之间的区别很微妙,可能会令人困惑,除非您了解变量声明也会创建财产(仅在variable Object上),并且Javascript(好吧,ECMAScript)中的每个属性都有描述其财产的特定标志——ReadOnly、DontEnum和DontDelete。

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

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

希望一切都有意义:)


[更新2010/12/16]

在ES5(ECMAScript 5;最近标准化,该语言的第5版)中,有一种所谓的“严格模式”——一种选择性语言模式,它稍微改变了未声明赋值的行为。在严格模式下,分配给未声明的标识符是ReferenceError。这样做的理由是捕捉意外分配,防止创建不需要的全局财产。一些较新的浏览器已经开始滚动支持严格模式。例如,请参见我的同胞表。


使用var总是一个好主意,可以防止变量扰乱全局范围,避免变量彼此冲突,导致不必要的覆盖。


另一个区别例如

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

虽然

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

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

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

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

my_var;

不能在全局范围或任何其他范围内工作。它应该具有如下值:

my_var = "value";

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

var my_var;

它的值未定义(有趣的是,它的值不为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 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);

结论无论是否声明有var(如a、b),如果它们在函数外部获取值,它们都将保留其值,并且通过脚本添加到各个函数内部的任何其他值也将保留。如果在函数(如c)中声明变量时没有var,它将像前面的规则一样,从现在起在所有函数中保留其值。要么在函数testVar1()中获得第一个值,要么仍保留该值,并在函数testVar2()中获取附加值如果变量仅在函数内部用var声明(如testVar1或testVar2中的d),则每当函数结束时,它都将是未定义的。所以它将是函数中的临时变量。


除非您希望将变量附加到浏览器中的窗口对象,否则应该使用var关键字。这里有一个链接,用和wihtout var关键字解释全局作用域和本地作用域之间的区别。

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

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

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


不要使用var!

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

使用常量和let

约95%的病例应使用常量。它使变量引用不能更改,因此数组、对象和DOM节点财产可以更改,并且应该是常量。

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

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


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

正如您预期的那样,以下代码段输出[“text”]:

函数var_fun(){let数组=[]array.push('text')返回数组}console.log(var_fun())

下面的代码段也是如此(请注意缺少的let before数组):

函数var_fun(){数组=[]array.push('text')返回数组}console.log(var_fun())

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

函数var_fun(){array=[];return new Promise(resolve=>resolve()).then(()=>{array.push('text')返回数组})}var_fun().then(result=>{console.log(result)})

但对多个对象的行为不同:

函数var_fun(){array=[];return new Promise(resolve=>resolve()).then(()=>{array.push('text')返回数组})}[1,2,3].对于每个(i=>{var_fun().then(result=>{console.log(result)})})

但是,使用let:

函数var_fun(){let数组=[];return new Promise(resolve=>resolve()).then(()=>{array.push('text')返回数组})}[1,2,3].对于每个(i=>{var_fun().then(result=>{console.log(result)})})


除了范围问题,一些人也提到了吊装,但并没有人举例说明。这里有一个全局范围:

console.log(noErrorCase);var noErrorCase=“您将到达该点”;

console.log(runTimeError);runTimeError=“您不会到达该点”;