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

时间:2009-09-24 08:54:04

标签: javascript keyword ecmascript-5

  

注意 :此问题是从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;

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

19 个答案:

答案 0 :(得分:1297)

如果你处于全球范围,那么差别不大。请阅读Kangax's答案以获取解释

如果你在一个函数中,那么 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

答案 1 :(得分:716)

存在差异

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

另一方面,

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

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

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

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

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

希望一切都有意义:))


[更新2010/12/16]

在ES5(ECMAScript 5;最近标准化,该语言的第5版)中,有一种所谓的“严格模式” - 一种选择加入语言模式,它稍微改变了未声明作业的行为。在严格模式下,对未声明标识符的分配是 ReferenceError 。其基本原理是捕获意外分配,防止产生不希望的全局属性。一些较新的浏览器已经开始支持严格模式。例如,请参阅my compat table

答案 2 :(得分:132)

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

最好将其视为“本地最近”之间的区别。最接近的肯定是全球性的,但情况并非总是如此。

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

答案 3 :(得分:78)

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

with (window) {
    //Your code
}

有关with - MDN

的更多信息

由于var在当前范围中声明变量,因此在窗口内声明var 与根本不声明它之间没有区别

当你不直接进入窗户时会出现差异,例如:在函数内部或块内部。

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

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

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

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

答案 4 :(得分:37)

总是使用var关键字来声明变量。为什么?好的编码实践本身就足够了,但是声明一个没有var关键字的变量意味着它在全局范围内声明(像这样的变量称为“暗示”)全球)。道格拉斯·克罗克福德recommends never using implied globals,并根据Apple JavaScript Coding Guidelines

  

在没有var的情况下创建的任何变量   关键字在全局范围内创建   并且不是垃圾收集的时候   函数返回(因为它没有   超出范围),提出   内存泄漏的机会。

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

答案 5 :(得分:27)

以下是一个很好的例子,说明如何通过var声明局部变量来解决这个问题:

<script>
one();

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

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

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

答案 6 :(得分:11)

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

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

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

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

答案 7 :(得分:9)

不要使用var

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

使用constlet

const应该用于95%的案例。它使得变量引用无法更改,因此数组,对象和DOM节点属性可以更改,并且可能应该是const

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

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

答案 8 :(得分:8)

另一个区别 e.g

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

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

答案 9 :(得分:8)

没有var - 全局变量。

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

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

答案 10 :(得分:7)

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

答案 11 :(得分:2)

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

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

答案 12 :(得分:2)

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

由于您预计以下代码段输出["text"]

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

console.log(var_fun())
&#13;
&#13;
&#13;

以下代码段也是如此(请注意let之前丢失的array):

&#13;
&#13;
function var_fun() {
  array = []
  array.push('text')
  return array
}

console.log(var_fun())
&#13;
&#13;
&#13;

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

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

var_fun().then(result => {console.log(result)})
&#13;
&#13;
&#13;

但有多种行为不同:

&#13;
&#13;
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)})
})
&#13;
&#13;
&#13;

然后使用let:

&#13;
&#13;
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)})
})
&#13;
&#13;
&#13;

答案 13 :(得分:1)

在代码中,如果你在不使用var的情况下使用变量,那么自动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 */
}

答案 14 :(得分:1)

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

See the script below in action here at 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.   
  3. 如果在函数内部声明变量没有var(如c),它将像前一个规则一样,从现在起它将保留其在所有函数中的值。要么它在函数testVar1()中得到它的第一个值,它仍保留该值并在函数testVar2()中获得附加值
  4.   
  5. 如果变量仅在函数内声明为var(如testVar1或testVar2中的d),则只要函数结束,它就会被取消定义。所以它将是函数中的临时变量。
  6.   

答案 15 :(得分:1)

除了范围问题外,有些人还提到hoisting,但没有人举一个例子。这是全球范围的一个:

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

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

答案 16 :(得分:0)

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

my_var;

无法在全局范围任何其他范围中工作。它应该具有如下价值:

my_var = "value";

另一方面,你可以定义像;

这样的变体
var my_var;

其值为undefined(其值不是null,并且有趣地不等于null。)。

答案 17 :(得分:0)

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

如果您运行此代码:

// index.html
<div id="app">
  <h1>My App</h1>
  <ul>
    <li><a v-link="{ name: 'sales' }">Go to /sales</a></li>
    <li><a v-link="{ name: 'sales.report' }">Go to /sales/report</a></li>
    <li><a v-link="{ name: 'sales.create' }">Go to /sales/create</a></li>
    <li><a v-link="{ name: 'sales.edit', params: { i: 2 } }">Go to /sales/edit/2</a></li>
    <li><a v-link="{ name: 'sales.list' }">Go to /sales/list</a></li>
  </ul>
  <router-view></router-view>
</div>

// index.js
var Root = Vue.extend({
  template:
    '<div class="root">' +
      '<h2>This is Root. I always show</h2>' +
      '<router-view></router-view>' +
    '</div>'
})

var SalesReport = Vue.extend({
    template: '<p>This is Sales Report</p>'
})

var SalesCreate = Vue.extend({
    template: '<p>This is Sales Create</p>'
})

var SalesEdit = Vue.extend({
    template: '<p>This is Sales Edit ({{ $route.params.i }})</p>'
})

var SalesList = Vue.extend({
    template: '<p>This is Sales List</p>'
})

// configure router
var router = new VueRouter()

router.map({
  '/': {
    component: Root,
  },
  '/sales': {
      name: 'sales',
      component: Root,
      subRoutes: {
        '/report': {
          name: 'sales.report',
          component: SalesReport
        },
        '/create': {
          name: 'sales.create',
          component: SalesCreate
        },
        '/edit/:i': {
          name: 'sales.edit',
          component: SalesEdit
        },
        '/list': {
          name: 'sales.list',
          component: SalesList
        }
      }
    }
})

// start app
var App = Vue.extend({})
router.start(App, '#app')

输出将显示为:false,false,true,true

因为它看到函数中的变量与它之外的变量分开,因此术语局部变量,这是因为我们在赋值中使用了var。如果你删除了函数中的var,那么它现在如下所示:

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

这是因为它不是在本地范围或函数中创建新变量,而是简单地使用全局变量并将它们重新指定为false。

答案 18 :(得分:0)

除非您打算在浏览器中将变量附加到window对象,否则应使用var关键字。 Here's a link that explains scoping and difference between glocal scoping and local scoping with and wihtout var keyword.

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

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

您可能还想查看hoisting in javascript