为什么Javascript中未定义的变量有时会计算为false,有时还会抛出未捕获的ReferenceError

Why does an undefined variable in Javascript sometimes evaluate to false and sometimes throw an uncaught ReferenceError?

本文关键字:ReferenceError 计算 Javascript 未定义 变量 为什么 false      更新时间:2023-09-26

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

if (!elem) {
   ...
}

目的是如果"elem"未定义,则块中的代码将执行。它通常有效,但有时浏览器会抛出一个错误,抱怨未定义的引用。这看起来很基本,但我找不到答案。

一个未定义的变量和一个已定义但值为undefined的变量之间有区别吗?这似乎完全没有直觉。

什么是ReferenceError

如ECMAScript 5所定义的,ReferenceError表示已检测到无效引用。这本身并不能说明什么,所以让我们再深入一点。

抛开严格模式不谈,当脚本引擎被指示获取引用的值时,就会发生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)是等效的。在其他执行上下文中,使用这样的检查没有多大意义,因为根据定义,这是您自己的代码创建的执行上下文,所以您应该知道哪些变量存在,哪些不存在。

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

if (typeof elem === "undefined")

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

一个未定义的变量和一个已定义但值为undefined的变量之间有区别吗?

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

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

与相比;

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

这似乎完全没有直觉。

Meh。。。我觉得不直观:

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

以下是Jon关于环境记录的解释示例:

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.
    }
};

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

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

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

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

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

edit我会软化这一点,说很少这样测试非全局变量的存在是有意义的。

当变量被声明但未初始化或与声明一起使用时,其值为"未定义"。当引用这个未定义的变量时,浏览器会发出确切的抱怨。这里的"reference"表示某段javascript代码正试图访问其属性或方法。例如,如果"elem"未定义,则会引发异常:

elem.id = "BadElem";

或者您使用try/catch:

try { x } catch(err){}

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

undefined=变量存在,但其中没有值

ReferenceError=变量不存在