ChatGPT解决这个技术问题 Extra ChatGPT

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

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

?

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

链接 var 声明时,在逗号后添加换行符会影响行为吗?变量 x=1, y=2, [返回]z=3;
如果您选择的变量名恰好是先前定义的全局变量,则未能使用“var”也会使您暴露。在这里查看我的悲伤之旅:stackoverflow.com/questions/16704014/…
@Ray Toal 的 meloncard 博客文章(绝对值得一读)已移至 blog.safeshepherd.com/23/how-one-missing-var-ruined-our-launch
我从没想过一首诗会激发我对程序问题的思考
@Gibolt 但看看问题日期,这是一个不公平的召唤 2009 年的问题来说明这一点。尽管如此,它在当前日期仍然有效,可维护性,有一堆不是“现代 JS”的代码。

A
AmericanUmlaut

如果您在全球范围内,那么差别不大。阅读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

“差别不大”==“没有差别”?
嗯,实际上是的,有区别:) 这种区别是否重要是另一个问题。进一步查看我的答案:stackoverflow.com/questions/1470488/…
我认为这可能是亚历克斯的观点,这就是他使用“等于”运算符编写它的原因!
这就像用轨道枪射击自己...忘记在变量之前放置“var”,最终修改范围链中的某个变量...尝试说服 Java/C/Python/等。开发者认为 JavaScript 是值得的。哈!相比之下,C/C++ 的陷阱看起来不错。想象一下必须调试 JavaScript……当然,有些人会这样做。还有很多用 JavaScript 编写的代码(不是简单的代码,请注意)......
如果您在全局范围内,则没有区别。 >>下面的答案中解释了一个区别
M
Massimiliano Kraus

有区别。

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

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

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

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

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

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

希望这一切都有意义:)

[2010/12/16 更新]

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


如果我没记错的话,我想我曾经找到了一种方法,能够通过一些 eval hack 来delete var 声明的变量。如果我记得确切的技巧,我会在这里发布。
@Mageek他可能正在考虑可删除的 eval 声明的变量。我曾经写过 blog post about this
有点离题,但在这里提到它以供参考。 "let" 与 "var" 非常相似,并且在 Mozilla 中受支持。主要区别在于 var 变量的范围是整个封闭函数,其中“let”仅限于其块
@kangax 如果 Alex 示例的最后两行混合在一起: var someObject = {}someObject.someProperty = 5 怎么办? someProperty 是否会成为全局对象,而它是其属性的对象仍然是本地对象?
@kangax 所称的 DontDelete 标志的规范名称是 configurable (= false),您可以阅读有关 Object.definePropertyObject.getOwnPropertyDescriptor 的信息
J
Jonathan Lonowski

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

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

/* 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 global = false; 的位置不是最近的范围 outer 吗?
@Snekse:当 var global = false; 声明时,'nearest' 不适用。在该声明中,'global' 被放置在 outer() 的范围内,因为在声明中使用了 'var'。因为inner()中没有使用'var',所以它会改变下一层的值,也就是outer()。
我想知道如果您将该行更改为 var global = local; 是否会更改评论,在这种情况下,本地的近处范围将是正在积极定义的“本地”外部范围。虽然如果您将同一行更改为 var global = global 会变得很奇怪,在这种情况下,搜索 global 的值时最近的范围将在全局窗口范围内上升一个级别。
t
thealtus

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

with (window) {
    //Your code
}

有关 with - MDN 的更多信息

由于 var 在当前范围内声明了一个变量,因此声明 var inside window 和完全不声明它没有区别。

当您不在窗口内时,例如在函数内或块内时,差异就出现了。

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

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

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

var 在当前作用域中声明一个变量

全局范围是窗口

不使用 var 隐式声明 var 在全局范围内(窗口)

使用 var 在全局范围(窗口)中声明变量与省略它相同。

使用 var 在不同于 window 的范围内声明变量与在没有 var 的情况下声明变量不同

始终明确声明 var 因为这是一个好习惯


我没有对你投反对票,但范围可能比窗口更好。你的整个解释有点迟钝。
我只是用它的名字来称呼事物,你想称它为“全局作用域”,没关系,但是按照惯例,客户端是窗口对象,它是作用域链的最后一个元素,这就是为什么你可以调用每个函数和窗口中的每个对象都没有写“窗口”。
+1 这是一个非常好的解释——我以前没有听说过这样的 var/no var 问题(没有双关语)。
这个答案的大部分在 ES6 中被 let 弃用。
@EvanCarroll 这个答案在技术上也是不正确的,因为省略 var 不会声明任何变量,而是在全局对象上创建一个可删除的属性,除了 ES5“使用严格”模式之外,大多数答案显然不正确,也让不是甚至在这个答案中都没有考虑,因为在提出问题时没有任何对 javascript 版本(昨天添加)的引用,这意味着参考标准(当时)是 ECMA 262 第 3 版。
C
Camille Goudeseune

始终使用 var 关键字来声明变量。为什么?良好的编码习惯本身就足够了,但省略它意味着它是在 global 范围内声明的(这样的变量称为“隐含”全局)。 Douglas Crockford recommends never using implied globals,并根据 Apple JavaScript Coding Guidelines

没有使用 var 关键字创建的任何变量都是在全局范围内创建的,并且在函数返回时不会被垃圾收集(因为它不会超出范围),这会带来内存泄漏的机会。


“良好的编码习惯”本身绝不应该是充分的理由。这相当于“互联网上的一些人说这就是我的代码应该看起来的样子”。这甚至比“我的老师说的”更有效,除非一个人至少模糊地理解了规则背后的原因。
@cHao 我认为如果它是推荐的最佳实践,good coding practice 始终是充分的理由,这是由几位 Javascript 作者推荐的。
@ChrisS:不,“良好的编码实践”本身并不是理由。它被认为是良好做法的原因很重要。除非那些作者告诉你他们为什么推荐它,否则他们的推荐应该没有任何分量。如果您不同意这些原因,那么您可以自由地认为这是不好的建议。如果你跟随它而不问为什么,那就是货物崇拜的开始。
m
mehulmpt

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

<script>
one();

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

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

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


哎呀!我可以想象那个错字可能导致的所有错误。
我很好奇,为什么你将 i 作为参数传递给 two()? (在 for 循环内)是多余的吗?
该参数在封装在 one() 函数中的 two() 函数中被忽略,因为函数 two() 是在没有参数的情况下定义的。您说的很对,因为它没有作用,所以不需要它。
错误或功能?
W
Waqar

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

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

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

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


如果使用 var 关键字声明变量,它将在运行时创建,所以它不应该更慢吗?因为另一个是在解析时创建的。
@RyuKaplan - 嘿,这是真的吗?我尝试使用谷歌搜索并无法获得有关该主题的任何信息!你有这个断言的来源权威吗?谢谢
@RyuKaplan 解析/编译与实际运行代码不同。
G
Gibolt

不要使用变量!

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

使用 const 并让

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

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

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


将所有“var”替换为“const”(全部替换)。您会很快注意到重新分配的变量在哪里。如果它们太多,则可能是反模式编码:大多数可重新分配的变量可以嵌入闭包中或作为对象属性。如果你有几个:对他们使用“让”。最后,如果某些变量根本没有用 'var' 声明,它们将保持未声明,并且仍然存在于全局空间中,请注意。关于@Gibolt 评论“在 for 循环内”,还建议在“95% 的情况下”避免此类循环;-):数组方法很棒。
通过说 const 应该在 95% 的情况下使用,似乎我们正在远离良好的实践并进入教条。
在一个替代方案是不使用任何关键字的问题上使用一个大而粗的“不要使用 var”是一种危险的方式来构建和格式化你的答案。不要低估一个人对阅读第二段的兴趣。有些人可能处于懒惰的心情或匆忙中,并且可能会因为它的结构和格式方式而从这个答案中得到错误的想法。您没有明确提到您不提倡将变量放在全局范围内。
P
Pranay Warke

另一个区别,例如

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

尽管

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

你能解释一下为什么它在用'var'定义的变量和没有用var定义的变量的情况下工作吗?在 var 的情况下,是否在评估赋值右侧之前创建变量?
@Lucek 因为 var a 被提升到范围的顶部并设置为 null ,它声明但不初始化变量,然后在赋值中你有一个未定义的 null 变量的引用,它的计算结果为 false,并将赋值设置为 { 2}。在后者中,您对属性 a 的属性 a 进行了赋值。您可以分配给不存在的属性 - 在分配时创建它,但是如果没有向您抛出 ReferenceError,您将无法从不存在的属性中读取。
@EvanCarroll:它被提升到范围的顶部并设置为 undefined 而不是 null。
k
kevinji

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


W
Waqar

没有 var - 全局变量。

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

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

3
3 revs, 3 users 58%

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

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

该功能绝不是“匿名的”。事实上,它的名字尽可能地显眼。
感谢您编辑您的答案,以回应 Ingo Bürk 的评论,以使“匿名功能”实际上是匿名的。
t
thisismydesign

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

如您所料,以下代码段输出 ["text"]

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

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

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

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

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

但与多个不同的行为不同:

函数 var_fun() { 数组 = []; return new Promise(resolve => resolve()).then(() => { array.push('text') return array }) } [1,2,3].forEach(i => { var_fun().然后(结果 => {console.log(结果)})})

但是使用 let :

函数 var_fun() { 让数组 = []; return new Promise(resolve => resolve()).then(() => { array.push('text') return array }) } [1,2,3].forEach(i => { var_fun().然后(结果 => {console.log(结果)})})


感谢@thisismydesign 的示例!关于最后两个示例,为什么倒数第二个示例记录一个包含 3 个元素的数组,其中包含三次文本,而最终示例仅记录数组中每个元素的“文本”一次? (我知道最后一个将“数组”声明为变量,因此在本地范围内,而倒数第二个示例省略了这一点,使“数组”成为隐含全局范围的一部分。)但是,为什么这会影响输出?是因为 forEach "i" 迭代了函数和所有全局变量吗?
D
Danrex

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

如果您运行此代码:

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 去掉,那么它现在看起来像这样:

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。


T
Tarik

我看到人们在声明带有或不带有 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);

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


感谢您花时间创建一个示例来演示此主题。上面的代码缺少下面的部分,因此您可能需要编辑答案: a = 1;// 在没有 var 的函数外部定义 var b = 1;// 在函数外部定义,使用 var alert("Starting outside of all functions ... \n \na, b 已定义但 c, d 尚未定义:\na:" + a + "\nb:" + b + "\n \n (如果我尝试显示未定义 c 的值或者 d,console.log 会抛出 'Uncaught ReferenceError: c is not defined' 错误并且脚本会停止运行!)");
A
Akash Arora

在代码中,如果您在不使用 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 */
}

d
deathangel908

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

console.log(noErrorCase); var noErrorCase = "你会到达那个点";

控制台.log(runTimeError); runTimeError = "你不会达到那个点";


u
umut

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

my_var;

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

my_var = "value";

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

var my_var;

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


my_var; 实际上是一个有效的表达式语句。
如果之前定义了变量,则它是有效的语句。否则它会抛出错误“...未定义”。
无论之前是否定义了变量,它都是有效的语句。 :) 有效的语句可能会引发错误,它不会使语句无效。
我对此感到困惑。什么是有效陈述?你能给我一个无效的陈述例子吗?
我不得不道歉——最近 ECMAScript 语法太多了。 my_var; 是有效的 expression statement/my_var; 将是无效语句。但正如我所说,这是语法推理,我很抱歉,我的评论实际上是不恰当的。
s
systemdebt

除非您打算将变量附加到浏览器中的窗口对象,否则您应该使用 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