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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9981104/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-26 08:24:56  来源:igfitidea点击:

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

javascript

提问by Gullbyrd

Everything I've ever read indicates that in Javascript, the boolean value of an undefined variable is False. I've used code like this hundreds of times:

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

if (!elem) {
   ...
}

with the intent that if "elem" is undefined, the code in the block will execute. It usually works, but on occasion the browser will throw an error complaining about the undefined reference. This seems so basic, but I can't find the answer.

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

Is it that there's a difference between a variable that has not been defined and one that has been defined but which has a value of undefined? That seems completely unintuitive.

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

回答by Jon

What is a ReferenceError?

什么是引用错误?

As defined by ECMAScript 5, a ReferenceErrorindicates that an invalid reference has been detected. That doesn't say much by itself, so let's dig a little deeper.

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

Leaving aside strict mode, a ReferenceErroroccurs when the scripting engine is instructed to get the value of a reference that it cannot resolve the base valuefor:

撇开严格模式不谈,ReferenceError当指示脚本引擎获取无法解析其基值的引用值时,会发生 a :

A Reference is a resolved name binding. A Reference consists of three components, the base value, the referenced name and the Boolean valued strict reference flag. The base value is either undefined, an Object, a Boolean, a String, a Number, or an environment record (10.2.1). A base value of undefined indicates that the reference could not be resolved to a binding. The referenced name is a String.

引用是解析的名称绑定。引用由三个部分组成,基值、引用名称和布尔值严格引用标志。基值是未定义的、对象、布尔值、字符串、数字或环境记录 (10.2.1)。未定义的基值表示无法将引用解析为绑定。引用的名称是一个字符串。

When we are referencing a property, the base value is the object whose property we are referencing. When we are referencing a variable, the base value is unique for each execution context and it's called an environment record. When we reference something that is neither a property of the base object value nor a variable of the base environment record value, a ReferenceErroroccurs.

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

Consider what happens when you type fooin the console when no such variable exists: you get a ReferenceErrorbecause the base valueis not resolvable. However, if you do var foo; foo.barthen you get a TypeErrorinstead of a ReferenceError-- a subtle perhaps but very significant difference. This is because the base valuewas successfully resolved; however, it was of type undefined, and undefineddoes not have a property bar.

想想,当你键入的内容会发生foo在当没有这样的变量存在控制台:你得到一个ReferenceError,因为基值无法解析。然而,如果你这样做了,var foo; foo.bar那么你会得到一个TypeError而不是一个ReferenceError——一个微妙的也许但非常重要的差异。这是因为基值被成功解析;但是,它的类型为undefined,并且undefined没有属性bar

Guarding against ReferenceError

防范 ReferenceError

From the above it follows that to catch a ReferenceError before it occurs you have to make sure that the base value is resolvable. So if you want to check if foois resolvable, do

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

if(this.foo) //...

In the global context, thisequals the windowobject so doing if (window.foo)is equivalent. In other execution contexts it does not make as much sense to use such a check because by definition it's an execution context your own code has created -- so you should be aware of which variables exist and which do not.

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

回答by Kris

Checking for undefined works for variables that have no value associated but if the variable itself hasn't been declared you can run into these reference issues.

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

if (typeof elem === "undefined")

This is a far better check as doesn't run the risk of the reference issue as typeof isn't a method but a keyword within JavaScript.

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

回答by Matt

Is it that there's a difference between a variable that has not been defined and one that has been defined but which has a value of undefined?

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

Yes. A undeclared variable will throw a ReferenceErrorwhen used in an expression, which is what you're seeing.

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

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

}

Compared to;

相比;

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

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

}

That seems completely unintuitive.

这似乎完全不直观。

Meh... what I find unintuitive:

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

if (y) // error, y is undeclared

var x = {};

if (x.someUndeclaredAttribute) // no error... someUndeclaredAttribute is implictly undefined.

回答by mathieu

Here's an example of Jon'sexplanation regarding environment records:

以下是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.
    }
};

回答by A.com

undefined = variable exists but has no value in it

undefined = 变量存在但没有值

ReferenceError = variable does not exist

ReferenceError = 变量不存在

回答by tim

or you use try/catch:

或者你使用 try/catch:

try { x } catch(err){}

This way you're not doing anything in case of an error but at least your script won't jump off the cliff...

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

回答by Pointy

In strict mode, it is an error:

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

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

It's always really been better to make an explicit test for globals:

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

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

It doesn't make sense to perform such a test for non-global variables. (That is, testing to see whether the variable is defined that way; it's fine to test to see whether a defined variable has a truthy value.)

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

editI'll soften that to say that it rarelymakes sense to thusly test for the existence of non-globals.

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

回答by Xie

When a variable is declared and not initialized or it's used with declaration, its value is "undefined". The browser complains exactly when this undefined variable is referenced. Here "reference" means some piece of javascript code is trying to visit an attribute or method of it. For example, if "elem" is undefined, this will throw an exception:

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

elem.id = "BadElem";