【问题标题】:What is the correct way to check if a global variable exists?检查全局变量是否存在的正确方法是什么?
【发布时间】:2012-07-21 22:24:31
【问题描述】:

JSLint 没有将此作为有效代码传递:

/* global someVar: false */
if (typeof someVar === "undefined") {
    var someVar = "hi!";
}

正确的方法是什么?

【问题讨论】:

  • 请注意,var 的范围不限于if 块。就好像你在if 上面写了var someVar。参考:developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
  • 在只阅读了这里答案中的代码而不是问题中的代码后,陷入了一个巨大的兔子洞。如果你想编写同时在 Nodejs 和浏览器上运行的代码,这检查变量是否未定义的正确方法,不管 JSLint 会怎么想。

标签: javascript global-variables jslint


【解决方案1】:
/*global window */

if (window.someVar === undefined) {
    window.someVar = 123456;
}

if (!window.hasOwnProperty('someVar')) {
    window.someVar = 123456;
}

【讨论】:

  • 你可以使用/*global window */,而不是/*jslint browser: true */
  • 要得到相同的结果,第二种解决方案实际上应该是if(!window.hasOwnProperty('someVar'))
  • 如果页面在您之前运行此脚本会怎样:undefined = 'some value'
  • 请注意,“window”本身并没有在 web worker 中定义。要获得最大兼容性,请先检查窗口是否存在。
  • @Offirmo 关于如何做到这一点有什么想法吗?在这种情况下,window 是一个全局变量,我们要检查它的存在——这当然是我们首先要解决的问题。
【解决方案2】:
/**
 * @param {string} nameOfVariable
 */
function globalExists(nameOfVariable) {
    return nameOfVariable in window
}

无论您是使用 var foo 还是 window.foo 创建全局变量都没有关系 — 在全局上下文中使用 var 创建的变量会写入到 window。

【讨论】:

  • 当然,你不必使用函数,你可以在任何地方简单地使用"foo" in window
  • 嗯,JSlint 说:Unexpected 'in'. Compare with undefined, or use the hasOwnProperty method instead. 那么,我猜,正确的方法是:window.hasOwnProperty("nameOfVar")
  • @Susei:jsLint 不正确。 .hasOwnProperty() 是错误的,因为可能有一个全局位于 window 的原型链的更下方。它仍然是一个全局变量,但.hasOwnProperty() 不会看到它。 inundefined 测试是这样做的方法。
  • 这在 NodeJS 终端中不起作用; window 在那里未定义。
  • 对于您可能希望在 JSX 中进行内联检查的 React 应用程序的好答案
【解决方案3】:

如果您只想分配一个不存在的全局变量,请尝试:

window.someVar = window.someVar || 'hi';

window['someVar'] = window['someVar'] || 'hi';

【讨论】:

  • 这是最优雅、最干净的解决方案。
  • 如果全局变量是假的,这将无法按预期工作。如果someVar 包含0'' 之类的值,它将为其分配'hi',而不是使用现有值。
【解决方案4】:

试试

variableName in window

typeof window[variableName] != 'undefined'

window[variableName] !== undefined

window.hasOwnProperty(variableName)

【讨论】:

  • 你试过在 JSLint 上测试这些吗? "'someVar' in window", "typeof window['someVar'] !== 'undefined'", "window['someVar'] !== undefined" (不将其转换为 "window.someVar !== undefined)在 JSLint 上不行。但无论如何,感谢您的出色回答 :)
  • "prop" in object 是绝对合法的 JavaScript。请记住,JSLint 是为您服务的,而不是您为 JSLint 服务的,而且 JSLint 不是 JavaScript。对我来说if ('prop' in obj) { do_it(); } 更清晰(即可读性和可维护性),然后是if (obj.prop !== undefined) { do_it(); }。在这种情况下,我建议您忽略 JSLint。另请参阅stackoverflow.com/questions/6824895/…
  • 你是绝对正确的,但我宁愿保持我的代码 JSLint 验证,因为它更容易维护。
【解决方案5】:

我认为这实际上是 JSLint 的一个问题。它会发出以下错误:

意外的“类型”。直接与“未定义”比较。

我认为这是个坏建议。在 JavaScript 中,undefined 是一个全局变量,通常是未定义的。但有些浏览器允许脚本对其进行修改,例如:window.undefined = 'defined'。如果是这种情况,直接与undefined 比较可能会导致意外结果。幸运的是,当前兼容 ECMA 5 的浏览器不允许分配给 undefined(并且会在严格模式下抛出异常)。

我更喜欢 typeof someVar === "undefined",就像你发布的那样,或者 someVar in window,就像 Susei 建议的那样。

【讨论】:

  • 今天特别重要,因为并不是所有的 JS 都可以在浏览器中运行。如果您正在编写一个库,您希望您的代码既可以在浏览器上运行,也可以在不存在 window 的 nodejs 等运行时运行。
【解决方案6】:
if (typeof someVar === "undefined") {
    var someVar = "hi!";
}

将检查someVar(本地或全局)是否未定义。

如果要检查全局变量,可以使用

if(window['someVar'] === undefined) {
    ...
}

假设这是在浏览器中:)

【讨论】:

    【解决方案7】:

    bfavaretto 不正确。

    将全局 undefined 设置为一个值不会改变对象针对 undefined 的测试。在你最喜欢的浏览器 JavaScript 控制台中试试这个:

    var udef; var idef = 42;
    alert(udef === undefined); // Alerts "true".
    alert(idef === undefined); // Alerts "false".
    window.undefined = 'defined';
    alert(udef === undefined); // Alerts "true".
    alert(idef === undefined); // Alerts "false".
    

    这仅仅是因为 JavaScript 忽略了所有试图在未定义变量上设置的值。

    window.undefined = 'defined';
    alert(window.undefined); // Alerts "undefined".
    

    【讨论】:

    • 您不应使用“答案”部分来反驳他人的答案。如果您认为其他人的答案不起作用,请就您预见的问题对他们的答案发表评论,以便他们解决问题,或者为问题提供您自己的有效解决方案。
    • 这是相关的,但它没有回答问题。我知道这太长了,不能作为评论发表,也许你也可以回答你不同意下面的问题?
    • 您本可以对我的回答发表评论,只是为了让我知道您不同意,我只是偶然看到您的回答。您对我们“最喜欢的浏览器”的看法是正确的,问题是旧浏览器并没有阻止这一点。我将编辑我的答案以使其更清楚。
    • 不幸的是,尽管现代浏览器有限制,undefined 仍然可以修改:这个函数是完全合法的:function foo(undefined, x) { if (x === undefined) { alert('undefined!'); } }。例如,如果您拨打foo(3),它将不会发出警报。教训是“未定义”并不总是对全局属性的引用。
    【解决方案8】:

    这将是一种执行检查的简单方法。

    但如果 variableName 被声明并分配了 boolean value: false ,则此检查将失败

    if(window.variableName){
    
    }
    

    【讨论】:

    • 如果variableName 有任何虚假值(例如空字符串),这将不起作用,因此这可能不是一个足够的解决方案。
    【解决方案9】:

    从 ES6 开始,大多数其他答案,包括已接受的答案,都是不正确的,因为由 letconst 定义的全局变量,或由 class 声明产生的全局变量在全局对象上没有相应的属性(window 在浏览器中,或global 在 node.js 中)。其中一些——主要是使用typeof的那些——也可能被存在但设置为undefined的全局变量所欺骗。

    测试全局变量是否存在的唯一完全通用的方法——无论它是使用varletconst 声明的,还是通过functionclass 声明创建的,通过赋值(即,myVar = value 在程序的顶层,没有任何myVar 声明)或通过在全局对象上创建属性(即window.myVar = value)创建—试图通过全局访问它eval 看看是否抛出了TypeError。

    (这构建了on an idea presented by Ferran Maylinch,但有一个技巧可以确保即使封装在函数中也能正常工作。)

    function globalExists(varName) {
      // Calling eval by another name causes evalled code to run in a
      // subscope of the global scope, rather than the local scope.
      const globalEval = eval;
      try {
        globalEval(varName);
        return true;
      } catch (e) {
        return false;
      }
    }
    
    undeclared = undefined;
    const myConst = undefined;
    let myLet;
    var myVar;
    
    globalExists('undeclared')    // => true
    globalExists('myConst')       // => true
    globalExists('myLet')         // => true
    globalExists('myVar')         // => true
    globalExists('nonexistent')   // => false
    globalExists('globalExists')  // => true - can see itself.
    globalExists('varName')       // => false - not fooled by own parameters.
    globalExists('globalEval')    // => false - not fooled by local variable.
    

    请注意,这使用了eval,因此所有常见的警告都适用:您不应提供不受信任的值作为参数,如果您必须使用不受信任的值,则应检查以确保 varName 是一个有效的 JavaScript 标识符。这样做超出了这个问题的范围,但可以使用(rather complex) regular expression 来完成——请注意,正确的正则表达式取决于您使用的 ECMAScript 版本,代码是脚本还是(ES6)模块,是否它在异步函数中,等等。

    【讨论】:

      【解决方案10】:

      我认为最好的解决方案如下:

      if(window.hasOwnProperty('foo')) {
          console.log('Variable is not declared');
      }
      

      如果变量已声明但未分配 (var foo;),则以下解决方案将不起作用。

      typeof foo === 'undefined'
      

      【讨论】:

      • 我发誓我已经看到当变量未定义时在typeof 上引发错误的代码,但是typeof 现在似乎可以在任何地方工作。从节点 (node -e "console.log(typeof foo === 'undefined')")、开发工具控制台 (console.log(typeof foo === 'undefined') // true) 和文件 (node test.js // true) 交互,即使使用 "use strict";
      【解决方案11】:

      如果您不确定是否定义了全局变量,您可以随时尝试访问它,看看会发生什么。

      function node_env(name) {
          try {
              return process.env[name];
          } catch (ignore) {}
      }
      

      【讨论】:

        猜你喜欢
        • 2019-12-11
        • 1970-01-01
        • 2019-09-16
        • 2011-07-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多