声明没有var关键字的变量

时间:2011-07-31 09:20:40

标签: javascript variables global-variables declaration

在w3schools写道:

  

如果声明变量而不使用“var”,则变量始终变为GLOBAL。

在函数内声明全局变量是否有用?我可以想象在某个事件处理程序中声明一些全局变量,但它有什么用呢?更好地使用RAM?

8 个答案:

答案 0 :(得分:81)

不,没有RAM好处或类似的东西。

学校正在谈论的是我称之为The Horror of Implicit Globals的内容。考虑这个功能:

function foo() {
    var variable1, variable2;

    variable1 = 5;
    varaible2 = 6;
    return variable1 + variable2;
}

看起来很简单,但由于NaN行上的拼写错误,它会返回11而不是varaible2 = 6;。它创建了一个带有拼写错误名称的全局变量:

function foo() {
    var variable1, variable2;

    variable1 = 5;
    varaible2 = 6;
    return variable1 + variable2;
}
console.log(foo());     // NaN
console.log(varaible2); // 6?!?!?!

这是因为函数分配给varaible2(注意拼写错误),但varaible2未在任何地方声明。通过JavaScript中作用域链的机制,这最终成为对全局对象(您可以在浏览器上以window访问)的(新)属性的隐式赋值。 / p>

这只是松散模式JavaScript的“功能”,分配给完全未声明的标识符不是错误;相反,它在全局对象上创建属性,全局对象上的属性是全局变量。 (通过ES5,所有全局变量都是全局对象的属性。但是,从ES2015开始,添加了一种新的全局,它不是全局对象的属性。全局范围let,{{1 }和const创建新的全局。)

我的例子是一个错字,当然,如果你愿意,你可以故意这样做。毕竟,这是语言中明确定义的一部分。所以:

class

...未声明myNewGlobal = 42; 的任何地方都会创建新的全局。

但我强烈建议不要故意这样做:它使代码难以阅读和维护,并且当代码变得更加普遍和普遍时,代码将与JavaScript模块不兼容。如果你真的需要在运行时从一个函数内创建一个全局变量(已经是一个红色的标志,但它有正当理由),可以通过分配myNewGlobal上的属性(或任何引用的属性)明确地做到这一点。环境中的全局对象;浏览器上的window

window

事实上,我建议使用ES5的strict mode。严格模式会将未声明的标识符分配给错误,而不是静默创建全局。如果我们一直在使用严格模式,那么上面window.myNewGlobal = 42; 的问题会更容易诊断:

foo


有点切向,但总的来说我建议尽可能避免使用全局变量。全局命名空间已经非常混乱在浏览器上。浏览器为DOM中的每个元素创建一个全局"use strict"; // Turns on strict mode for this compilation unit function foo() { var variable1, variable2; variable1 = 5; varaible2 = 6; // <=== ReferenceError return variable1 + variable2; } console.log(foo());,对于大多数具有id的元素,并且有几个自己的预定义全局变量(如name),这很容易发生冲突用你的代码。

相反,只需定义一个不错的范围函数并将符号放入其中:

title

如果你这样做,你可能想要启用严格模式:

(function() {
    var your, symbols, here, if_they_need, to_be_shared, amongst_functions;

    function doSomething() {
    }

    function doSomethingElse() {
    }
})();

...如上所述,其优点是可以将未申报标识符的分配转换为错误(以及various other helpful things)。

请注意,在JvaScript 模块中(在ES2015中添加,但现在才开始寻找自己的方式),默认情况下启用严格模式。 ((function() { "use strict"; var your, symbols, here, if_they_need, to_be_shared, amongst_functions; function doSomething() { } function doSomethingElse() { } })(); 定义也是如此,这也是ES2015中的新定义。)

答案 1 :(得分:16)

忘记var时的副作用

隐含全局变量和明确定义的变量之间存在一点细微差别。 不同之处在于能够使用delete运算符取消定义这些变量:

•使用var创建的全局变量(在任何函数之外的程序中创建的全局变量) 无法删除。

•没有var创建的隐含全局变量(无论是否在函数内创建)都可以 删除。

这表明隐含的全局变量在技术上不是真正的变量,但它们是属性 全球对象。可以使用delete运算符和变量删除属性 不能:

// define three globals
var global_var = 1;
global_novar = 2; // antipattern
(function () {
   global_fromfunc = 3; // antipattern
}());
// attempt to delete
delete global_var; // false
delete global_novar; // true
delete global_fromfunc; // true
// test the deletion
typeof global_var; // "number"
typeof global_novar; // "undefined"
typeof global_fromfunc; // "undefined"

在ES5严格模式下,分配未声明的变量(例如两个反模式 在前面的代码片段中会抛出一个错误。

JavaScript模式,由Stoyan Stefanov(O'Reilly)撰写。版权所有2010 Yahoo!,Inc.,9780596806750。

答案 2 :(得分:3)

全局变量的唯一用途是,如果您需要全局访问它们。在这种情况下,您应该使用函数外部的var关键字来声明它们,以明确您确实要创建全局变量,并且在尝试声明本地变量时不会忘记var变量

通常,您应该尝试对代码进行范围调整,以便在全局范围内尽可能少地使用代码。您在脚本中使用的全局变量越多,您在另一个脚本中使用它的可能性就越小。

通常,函数中的变量应该是局部变量,以便在退出函数时它们消失。

答案 3 :(得分:2)

有时在函数内部创建新的全局可访问属性很有用,以后可以通过引用窗口对象轻松访问这些属性(所有全局声明的属性都附加到窗口对象)。

然而,由于通常会声明任何可全局访问的内容,因此可能会导致以后出现问题,因为这些属性很容易被覆盖等。只需将值作为参数传递给函数并检索其结果就好了。

答案 4 :(得分:1)

主要问题是其他人可能已经在使用同名的全局。

然后,当您更改全局值时,您将覆盖其值。

稍后使用全球时,它将神秘地改变。

答案 5 :(得分:1)

在函数内部不使用var,let或const声明变量比在函数内部使用var,let或const声明变量更有用。而且,正如之前对该问题的回答所指出的那样,局部函数隐式全局声明在声明它们的函数范围之外可能会造成混乱和问题。

我想谈谈w3schools报价以及该问题以前的答案中所缺少的一些细微之处。

首先,如果您从不调用生成隐式全局变量的函数,则不会生成任何隐式全局变量。这与w3schools的报价有微妙的区别,因为它违反了他们声明的“始终”部分。

function generateImplicitGlobals(){
  x = "x";
  window.y = "y";
}

// before calling the generateImplicitGlobals function, we can safely see that the x and y properties of the window object are both undefined:
console.log("before calling the generateImplicitGlobals function, properties x and y of the window object are: " + window.x + " and " + window.y);

// before calling the generateImplicitGlobals function, we can test for the existence of global variables x and y; note that we get errors instead of undefined for both.
try{
  console.log("before calling the generateImplicitGlobals function, x is: " + x);
}
catch(e){
  console.log("before calling the generateImplicitGlobals function, an attempt to reference some global variable x produces " + e);
}

try{
  console.log("before calling the generateImplicitGlobals function, y is: " + y);
}
catch(e){
  console.log("before calling the generateImplicitGlobals function, an attempt to reference the global variable b also produces " + e);
}
诚然,我确信w3schools知道在调用函数之前不会在函数内部进行隐式全局声明,但是对于刚接触javascript的人们来说,从给定的信息中可能并不清楚。

关于先前答案的微妙之处,一旦调用了generateImplicitGlobals函数,我们可以看到尝试访问window.x属性或全局变量x的尝试返回相同的值(而window.y属性和全局变量y变量返回相同的值)。当从generateImplicitGlobals函数内部或外部调用时,这些语句为true。

function generateImplicitGlobals(){
  x = "x";
  window.y = "y";
  console.log("inside the function, x and window.x are: " + x + " and " + window.x);
  console.log("inside the function, y and window.y are: " + y + " and " + window.y);
}

// now, call the generator, and see what happens locally and globally.
generateImplicitGlobals();
console.log("after calling the generateImplicitGlobals function, x, window.x, y, and window.y are: " + x + ", " + window.x + ", " + y + ", and " + window.y);

答案 6 :(得分:1)

无论如何,可以将值得的“变量”附加到函数的参数列表中。

如果你给一个参数分配一个新值,它不会影响调用者对该参数的看法,(即使是一个对象,指向该对象本身的变量对于函数来说也是唯一的。该对象的属性可以修改,但完全替换对象对原始对象没有影响)。

为命名参数分配一个新值会临时替换当前作用域(和派生作用域)。

从解释者的角度来看,参数和变量在这方面没有区别。即使调用者不提供值,每个未使用的参数也隐含一个空变量

此外,您可以通过简单地将值分配给命名函数来创建外部可用的“持久”变量 - 它们实际上是对象本身。这甚至可以从函数内部完成。


  function noVars(a1,/*vars=*/v1,v2,v3) {
    if (noVars.lastA1===a1) return noVars.lastAnswer;

    noVars.lastA1=a1;

    v1=a1*a1;
    v2=v1*v1;
    v3=v2*v2*v2;

    noVars.lastAnswer = a1+v1+v2+v3;

    return noVars.lastAnswer;
  }

主要区别在于这些“持久”值在每次调用之间都存在,而 var,let,arguments 中的值在每次调用开始时都是“空容器”。参数可以由调用者预设,否则它们是“未定义的”。

这可能被视为滥用 agument 系统,我认为它以非标准方式使用它。对阻止此工作的 javascript 规范的任何更改也会破坏将值传递给函数总是“按值”的事实,即使是对象(对象本身就是引用的事实是无关紧要的)。

这也可以:


  var noVars = function (a1,/*vars=*/v1,v2,v3) {
    if (noVars.lastA1===a1) return noVars.lastAnswer;

    noVars.lastA1=a1;

    v1=a1*a1;
    v2=v1*v1;
    v3=v2*v2*v2;

    noVars.lastAnswer = a1+v1+v2+v3;

    return noVars.lastAnswer;
  };

答案 7 :(得分:0)

我想说这可能会损害您的安全性甚至代码的稳定性。

如上所述,您可能仅通过拼写错误的变量就可能犯错,而解决方案就是关键字"use strict";
声明此关键字后,将引发错误:Uncaught ReferenceError: foo is not defined

它也指安全代码:
 1.在编写安全代码时,我们不希望在变量实际声明的地方访问变量。不要在不需要时声明全局变量。
 2.务必仔细阅读警告并加以解决。使用"use strict";,JSlint和其他工具查看并解决警告,以使您的代码更好。