声明没有var关键字的变量

IT技术 javascript variables global-variables declaration
2021-01-17 12:06:24

在 w3schools 有写:

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

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

6个回答

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

w3schools 谈论的是我称之为隐式全局变量的恐怖考虑这个函数:

function foo() {
    var variable1, variable2;

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

看起来很简单,但它返回的是NaN,而不是11,因为行中的错字varaible2 = 6;它创建了一个带有拼写名称的全局变量:

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

这只是松散模式 JavaScript 的一个“特性”,分配给一个完全未声明的标识符不是错误;相反,它在全局对象上创建一个属性,全局对象上的属性是全局变量。(最多通过ES5,所有全局是全局对象。由于ES2015的,虽然加入了一种新的全球性不是全局对象的属性。全球范围的特性letconst以及class创建新的全球.)

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

myNewGlobal = 42;

...任何myNewGlobal未声明的地方都将创建新的全局。

但我强烈建议永远不要故意这样做:它使代码难以阅读和维护,并且当 JavaScript module变得更加普遍和广泛时,这些代码将与 JavaScript module不兼容。如果您确实需要在运行时从函数内部创建全局变量(已经是一个危险信号,但有正当理由),请通过分配给 on window(或任何引用您环境中的全局对象的属性)来显式执行; 它window在浏览器上):

window.myNewGlobal = 42;

事实上,我建议使用 ES5 的严格模式严格模式使分配给未声明的标识符成为错误,而不是默默地创建全局。如果我们一直使用严格模式,foo上面的问题会更容易诊断:


有点切线,但总的来说,我建议尽可能避免使用全局变量。全局命名空间在浏览器上已经非常非常混乱了。浏览器使用 为 DOM 中的每个元素创建一个全局变量id,对于大多数具有 的元素name,并且有几个自己的预定义全局变量(如title),它们很容易与您的代码发生冲突。

相反,只需为自己定义一个很好的作用域函数并将您的符号放入其中:

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

    function doSomething() {
    }

    function doSomethingElse() {
    }
})();

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

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

    function doSomething() {
    }

    function doSomethingElse() {
    }
})();

...正如前面提到的,它的优点是将未声明的标识符的赋值转化为错误(以及其他各种有用的东西)。

请注意,在 JavaScriptmodule中(在 ES2015 中添加,但现在才开始流行),默认情况下启用了严格模式。(这也是class定义的情况,也是 ES2015 中的新内容。)

如果没有错误,程序运行得很好。全局变量的问题是心理问题。我在调试一个实际问题时来到这里,想知道是否是未声明的变量导致了它,现在我知道这不是问题所在。
2021-03-12 12:06:24
@Roland:答案中没有出现“bug”这个词,不太确定你指的是什么。但是隐式全局变量通常是意外创建的(拼写错误),这肯定会导致错误。这就是我使用严格模式(和/或 lint 工具)的部分原因。
2021-03-13 12:06:24
虽然我同意我不喜欢全局变量,但没有错误。您的代码只是按照预期将 x + y 返回为 11。
2021-03-20 12:06:24
@Roland:嗯,我很高兴你的问题不是这个。对于许多人来说,确实如此,因为他们不小心分配到ietm而不是item或类似的,并且在任何地方都没有迹象(除了代码不起作用)。
2021-03-25 12:06:24
我花了很大的精力才发现长答案和 w3schools 链接并没有说未声明的 var 本身就是一个错误。您对拼写错误和错误(错误)可能性的观察应该是充分的答案。
2021-04-06 12:06:24

忘记 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。

重新“隐含的全局变量在技术上不是真正的变量,但它们是全局对象的属性”我会以不同的方式描述它。“用于全局范围的变量”和“隐含的全局变量”都将属性附加到窗口对象。唯一的区别(如果var声明是在全局范围内,而不是在函数内),就是使用 时var,属性有configurable: falseMDN 删除操作符
2021-03-14 12:06:24
@Anurag_BEHS - 不确定您在 w3schools tryit 中输入的确切代码,以获得 的“编号​​” global_novar,但我只是在那里进行了测试,并得到了与答案中所示相同的结果。我建议alert(delete global_novar);- 返回true还是false如果它返回false,那么您所做的与此答案中显示的有所不同。
2021-03-22 12:06:24
//变量结果的类型需要稍作修改当我尝试在w3school编译器中运行上面的变量声明时,我收到了警报(typeof global_var);//数字警报(全球诺瓦的类型);//数字警报(typeof global_fromfunc);//未定义
2021-04-09 12:06:24
但这并不是唯一的区别。在全局上下文中使用 var 声明的变量表现为变量(例如提升),而全局对象上的属性表现为......好吧,就像属性一样。他们是两个不同的东西。
2021-04-09 12:06:24

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

通常,您应该尝试限定代码的范围,以便在全局范围内尽可能少地需要。您在脚本中使用的全局变量越多,将其与另一个脚本一起使用的机会就越少。

通常函数中的变量应该是局部的,这样当你退出函数时它们就会消失。

@xralf:所有语言都允许可能被滥用的构造。while (true);想到。
2021-03-11 12:06:24
奇怪的是,javascript 允许无用的构造,但只会在我们输入错误时造成麻烦。
2021-04-07 12:06:24

在不使用 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 函数内部或外部调用时,这些语句为真。

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

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

然而,通常声明任何东西都是全局可访问的,它可能会在以后导致问题,因为这些属性很容易被覆盖等。简单地将值作为参数传递给函数并检索它们的结果要好得多。