使用“var”来声明变量是可选的吗?

IT技术 javascript
2021-01-16 21:04:40

“var”是可选的吗?

myObj = 1;

与...一样 ?

var myObj = 1;

我发现它们都在我的测试中工作,我认为var是可选的。是对的吗?

6个回答

它们的意思不同。如果您使用var变量在您所在的范围内声明(例如函数)。如果您不使用var,则变量会在作用域层中冒泡,直到遇到给定名称的变量或全局对象(窗口,如果您在浏览器中执行此操作),然后将其附加到此处。非常类似于全局变量。但是,它仍然可以被删除delete(很可能被其他人的代码也没有使用var)。如果var在全局作用域中使用,该变量是真正的全局变量,不能删除。

在我看来,这是 javascript 中最危险的问题之一,应该弃用,或者至少对警告提出警告。原因是,很容易忘记var并意外地将公共变量名称绑定到全局对象。这会产生奇怪且难以调试的行为。

@The Elite Gentleman:是的,它确实使它成为一个全局变量。
2021-03-12 21:04:40
从 ECMAScript 5 严格模式中删除了自动全局变量,这基本上是一种隐式弃用。希望如果您忘记var在非严格模式下,实现会发出警告
2021-03-21 21:04:40
实际上不,在不使用的var情况下分配给变量不会使其成为global它会导致 JS 向上遍历作用域链,如果变量之前没有在任何地方使用过,最终会到达全局对象。如果变量var在 global 之前的某个地方声明的,那就是将使用的范围。它也是 JS 的工作原理以及它真正强大的原因的一个组成部分,因此我不会将其描述为“陷阱”。
2021-03-27 21:04:40
@codemeit :javascript 充满了这样的陷阱,但总而言之,它是一种美丽且令人愉悦的语言。不要讨厌它。只需了解陷阱并将它们排除在您的代码之外。
2021-04-02 21:04:40
@deceze:遍历作用域链是一件好事,但是如果找不到任何东西,则将其添加到全局作用域中是一个陷阱。
2021-04-05 21:04:40

这是 Javascript 的棘手部分之一,但也是其核心功能之一。一个用var“开始它的生命”声明的变量就在你声明它的地方。如果您省略var,就好像您在谈论您以前使用过的变量。

var foo = 'first time use';
foo = 'second time use';

关于作用域,变量自动变为全局正确的。相反,Javascript 将遍历作用域链以查看您之前是否使用过该变量。如果它找到以前使用的同名变量的实例,它将使用该实例以及它声明在的任何范围。如果它在任何地方都没有遇到该变量,它最终将命中全局对象(window在浏览器中)并将变量附加到它。

var foo = "I'm global";
var bar = "So am I";

function () {
    var foo = "I'm local, the previous 'foo' didn't notice a thing";
    var baz = "I'm local, too";

    function () {
        var foo = "I'm even more local, all three 'foos' have different values";
        baz = "I just changed 'baz' one scope higher, but it's still not global";
        bar = "I just changed the global 'bar' variable";
        xyz = "I just created a new global variable";
    }
}

当与嵌套函数和回调一起使用时,这种行为非常强大。functions了解作用域是什么以及如何工作是 JavaScript 中最重要的事情。

是不是var foo = 1移到当前函数作用域的顶部,而不是你声明它的地方?foo = 100; bar = 200; (function fooBarDeluxeEdition() { bar = 300; //var bar = 400; // try uncommenting this for fun! :) }()); document.write(bar);
2021-03-27 21:04:40
@carl 好吧,有点公平。“在范围内开始它的生命”那个更合适?:)
2021-03-28 21:04:40
@carl 语句本身没有移到顶部,没有。本质上,一条var语句在当前范围内保留了变量名,它会以一个undefined开始初始值的分配只会发生在你写的地方var .. = ..
2021-03-29 21:04:40
@deceze 是的,我有点跑题了。我的观点是答案(否则很好)指出变量从var语句开始它的生命但实际上,如果我没记错的话,var在执行函数作用域之前会扫描所有语句,因此所有变量都在作用域的开头“诞生”,即使它们被分配在var. 这可能是人为的,但我的示例显示了一个场景,您可能会挠头一段时间(尤其是如果您是多页面功能的爱好者)。
2021-04-03 21:04:40
这确实是最好的答案,因为了解作用域链的实际行为是了解函数式 Javascript 如何工作的关键——即使您不喜欢以函数式风格进行编码,考虑到有多少常用库,也很高兴知道确实使用功能风格。
2021-04-07 21:04:40

不,它们不是等价的。

随着myObj = 1;你使用全局变量。

后一个声明创建一个局部于您正在使用的范围的变量。

尝试以下代码以了解差异:

external = 5;
function firsttry() {
  var external = 6;
  alert("first Try: " + external);
}

function secondtry() {
  external = 7;
  alert("second Try: " + external);
}

alert(external); // Prints 5
firsttry(); // Prints 6
alert(external); // Prints 5
secondtry(); // Prints 7
alert(external); // Prints 7

第二个函数改变全局变量“external”的值,但第一个函数没有。

小心说“您正在使用全局变量”。“myObj = 1;” 指外部作用域中的变量,可能不是全局变量。但是,您的示例确实引用(并可能隐式声明)全局范围内的变量。
2021-03-26 21:04:40

除了本地与全局之外,还有更多内容。创建的全局变量与var没有创建的全局变量不同。考虑一下:

var foo = 1; // declared properly
bar = 2; // implied global
window.baz = 3; // global via window object

根据目前的答案,这些全局变量foobar、 和baz都是等价的。这是不是这种情况。用 制作的全局变量var(正确)分配了内部[[DontDelete]]属性,因此它们不能被删除。

delete foo; // false
delete bar; // true
delete baz; // true

foo; // 1
bar; // ReferenceError
baz; // ReferenceError

这就是为什么您应该始终使用var,即使对于全局变量也是如此。

我认为您的见解值得更多曝光,因此我编辑了所选答案以包含此信息。
2021-03-21 21:04:40

围绕这个主题有很多混乱,现有的答案都没有清楚直接地涵盖所有内容。以下是一些带有内联注释的示例。

//this is a declaration
var foo;

//this is an assignment
bar = 3;

//this is a declaration and an assignment
var dual = 5;

声明设置 DontDelete 标志。作业没有。

声明将该变量与当前作用域联系起来。

已分配但未声明的变量将寻找将其自身附加到的作用域。这意味着它将沿着作用域的食物链向上遍历,直到找到具有相同名称的变量。如果没有找到,它将附加到顶级范围(通常称为全局范围)。

function example(){
  //is a member of the scope defined by the function example
  var foo;

  //this function is also part of the scope of the function example
  var bar = function(){
     foo = 12; // traverses scope and assigns example.foo to 12
  }
}

function something_different(){
     foo = 15; // traverses scope and assigns global.foo to 15
}

为了非常清楚地描述正在发生的事情,对删除函数的分析广泛地涵盖了变量实例化和赋值。

我发现这是对该行为最简洁的解释和演示。我知道这是旧的,但它仍然有效,我认为可以通过调用每个函数后跟一个声明来改进它,foo以表明它在第一种情况下会导致错误,并在第二种情况下神奇地添加到全局范围. 如果你愿意,我可以自己编辑。
2021-03-21 21:04:40
“范围食物链”=>“范围链”
2021-03-29 21:04:40