为什么Javascript中的未定义变量有时会被评估为false,有时会抛出未被捕获的ReferenceError?

Gul*_*yrd 27 javascript

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

if (!elem) {
   ...
}
Run Code Online (Sandbox Code Playgroud)

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

是否存在尚未定义的变量与已定义但具有未定义值的变量之间的差异?这似乎完全不直观.

Jon*_*Jon 30

什么是ReferenceError?

如ECMAScript 5所定义,a ReferenceError表示检测到无效引用.这本身并不多说,所以让我们深入挖掘一下.

抛开严格模式,ReferenceError当指示脚本引擎获取无法解析基值的引用值时,会发生以下情况:

Reference是已解析的名称绑定.Reference由三个组件组成,基值,引用名称和布尔值严格引用标志.基值是undefined,Object,Boolean,String,Number或环境记录(10.2.1).基本值undefined表示无法将引用解析为绑定.引用的名称是String.

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

想想,当你键入的内容会发生foo在当没有这样的变量存在控制台:你得到一个ReferenceError,因为基值无法解析.但是,如果你这样做,var foo; foo.bar你会得到一个 - TypeError而不是ReferenceError- 一个微妙的但可能非常显着的差异.这是因为基值已成功解决; 然而,它是类型undefined,并undefined没有属性bar.

防范ReferenceError

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

if(this.foo) //...
Run Code Online (Sandbox Code Playgroud)

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


Kri*_*ris 6

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

if (typeof elem === "undefined")
Run Code Online (Sandbox Code Playgroud)

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


Mat*_*att 5

尚未定义的变量与已定义但值未定义的变量之间是否有区别?

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

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

}
Run Code Online (Sandbox Code Playgroud)

相比;

var y; // alert(y === undefined); // true

if (y) { // false, but no error

}
Run Code Online (Sandbox Code Playgroud)

这似乎完全不合常理。

......我觉得不直观:

if (y) // error, y is undeclared

var x = {};

if (x.someUndeclaredAttribute) // no error... someUndeclaredAttribute is implictly undefined.
Run Code Online (Sandbox Code Playgroud)

  • 全局变量的情况更不直观:`foo`抛出ReferenceError,而`window.foo`计算为false。 (2认同)