【问题标题】:Why does an undefined variable in Javascript sometimes evaluate to false and sometimes throw an uncaught ReferenceError?为什么 Javascript 中的未定义变量有时会评估为 false,有时会抛出未捕获的 ReferenceError?
【发布时间】:2012-04-02 17:42:39
【问题描述】:

我读过的所有内容都表明,在 Javascript 中,未定义变量的布尔值是 False。我已经使用了数百次这样的代码:

if (!elem) {
   ...
}

如果“elem”未定义,则块中的代码将执行。它通常可以工作,但有时浏览器会抛出一个错误,抱怨未定义的引用。这似乎很基本,但我找不到答案。

未定义的变量与已定义但值为 undefined 的变量之间是否存在差异?这似乎完全不直观。

【问题讨论】:

  • 刚来到这里,想发表关于“吊装”的评论。如果您在检查后声明变量 elem 并且在同一个函数(作用域)中,您将从函数顶部获得一个 undefined 值,直到您将一些值传递给它。

标签: javascript


【解决方案1】:

什么是 ReferenceError?

根据 ECMAScript 5 的定义,ReferenceError 表示检测到无效引用。这本身并不能说明太多,所以让我们深入挖掘一下。

抛开严格模式不谈,当指示脚本引擎获取它cannot resolve the base value 用于的引用值时,会出现ReferenceError

引用是已解析的名称绑定。参考由三个 组件、基值、引用名称和布尔值 严格参考标志。基值要么是未定义的,要么是对象, 布尔值、字符串、数字或环境记录 (10.2.1)。一个 undefined 的基值表示引用不能是 解决为绑定。引用的名称是一个字符串。

当我们引用一个属性时,基值是我们引用其属性的对象。当我们引用一个变量时,每个执行上下文的基值都是唯一的,它被称为环境记录。当我们引用既不是基础对象值的属性也不是基础环境记录值的变量的东西时,就会出现ReferenceError

考虑在不存在此类变量的情况下在控制台中键入 foo 时会发生什么:您会得到 ReferenceError,因为 基本值 不可解析。但是,如果您使用var foo; foo.bar,那么您会得到TypeError 而不是ReferenceError——这可能是一个微妙但非常显着的差异。这是因为基础值被成功解析;但是,它是undefined 类型,而undefined 没有属性bar

防范 ReferenceError

从上面可以看出,要在 ReferenceError 发生之前捕获它,您必须确保基值是可解析的。因此,如果您想检查foo 是否可解析,请执行

if(this.foo) //...

在全局上下文中,this 等于 window 对象,因此 if (window.foo) 是等效的。在其他执行上下文中,使用这样的检查没有多大意义,因为根据定义,它是您自己的代码创建的执行上下文——因此您应该知道哪些变量存在,哪些不存在。

【讨论】:

    【解决方案2】:

    检查未定义对没有关联值的变量有效,但如果变量本身尚未声明,您可能会遇到这些参考问题。

    if (typeof elem === "undefined")
    

    这是一个更好的检查,因为 typeof 不是方法,而是 JavaScript 中的关键字,因此不会冒引用问题的风险。

    【讨论】:

    • 这就是我最终要做的,但这还不够;在许多情况下,您还需要检查 null 或“”,因此您最终会得到一些非常丑陋的东西,例如“if (typeof x === 'undefined' || !x)...”
    • 我不太确定 elem 是什么,但你所描述的并不典型。必须检查 undefined、null 和 empty 有点,可能取决于您正在使用的内容。
    • typeof isn't a method but a keyword within JavaScript. 不是真的,typeof 是运算符而不是关键字,不像 varlet 是关键字,主要用于告诉 JS 分配内存用于某种持有指针/参考。
    【解决方案3】:

    未定义的变量与已定义但值为 undefined 的变量之间是否存在差异?

    是的。未声明的变量在表达式中使用时会抛出 ReferenceError,这就是您所看到的。

    if (x) { // error, x is undeclared
    
    }
    

    相比;

    var y; // alert(y === undefined); // true
    
    if (y) { // false, but no error
    
    }
    

    这似乎完全不直观。

    ...我觉得不直观:

    if (y) // error, y is undeclared
    
    var x = {};
    
    if (x.someUndeclaredAttribute) // no error... someUndeclaredAttribute is implictly undefined.
    

    【讨论】:

    • 全局变量 case 更不直观:foo 抛出 ReferenceError,而 window.foo 计算结果为 false。
    【解决方案4】:

    这是Jon's关于环境记录的解释示例:

    var bar = function bar() {
        if (!b) { // will throw a reference error.
        }
    },
    foo = function foo() {
        var a = false;
    
        if (a) {
            var b = true;
        }
    
        if (!b) { // will not throw a reference error.
        }
    };
    

    【讨论】:

      【解决方案5】:

      在严格模式下,这是一个错误:

      function a() {
        "use strict";
        if (!banana) alert("no banana"); // throws error
      }
      

      对全局变量进行显式测试总是更好:

      if (!window['banana']) alert("no banana");
      

      对非全局变量执行这样的测试是没有意义的。 (也就是说,测试变量是否是这样定义的;测试定义的变量是否具有真值是可以的。)

      edit 我会软化这个说法,很少因此测试非全局变量的存在是有意义的。

      【讨论】:

        【解决方案6】:

        当一个变量被声明但未初始化或与声明一起使用时,其值为“未定义”。当引用这个未定义的变量时,浏览器会准确地抱怨。这里的“引用”意味着一些 javascript 代码试图访问它的属性或方法。例如,如果 "elem" 未定义,则会抛出异常:

        elem.id = "BadElem";
        

        【讨论】:

          【解决方案7】:

          或者你使用 try/catch:

          try { x } catch(err){}
          

          这样你在出错的情况下不会做任何事情,但至少你的脚本不会跳崖......

          【讨论】:

            【解决方案8】:

            undefined = 变量存在但没有值

            ReferenceError = 变量不存在

            【讨论】:

              猜你喜欢
              • 2016-12-18
              • 2019-03-05
              • 2014-04-13
              • 2021-02-08
              • 1970-01-01
              • 2012-02-01
              • 2014-06-21
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多