JavaScript中如何检查空值/未定义值

8

这段代码能不能

if (typeof foo != "undefined" && foo !== null) { }  

能够安全地重构到这段代码中吗?
if (foo != null) { }

这是完全相同的吗?(如果不是,有什么不同?)

可能是 https://dev59.com/f3RA5IYBdhLWcg3w2x2W 中的重复问题。 - Hps
@Hps 我在SO上搜索了一下。这个问题从未被提问过。 - Šime Vidas
3个回答

11

其实不是这样的。如果foo没有被声明,你在第二个例子中会抛出一个ReferenceError异常。

另一方面,你可以使用typeof运算符来安全地检查未声明的变量是否未定义。


@Daniel 我不明白。如果我有 var foo; 然后运行第二个片段,在 Chrome 中不会抛出错误(至少不会)。 - Šime Vidas
@Sime:尝试使用if (aNewFoo != null) { }而不是在之前声明var aNewFoo;。然后再尝试if (typeof aNewFoo != 'undefined') { },同样不需要声明变量...这就是区别所在。 - Daniel Vassallo
@丹尼尔,所以如果 foo 没有声明,那么会抛出错误,但如果它被声明了但恰好保存了未定义的值,则不会抛出错误。是这样吗? - Šime Vidas
@Sime: 是的,完全正确。因此 typeof x === 'undefined' 可以检查那些未被声明或已被设置为 undefined 的变量。这是你两个示例之间的主要区别。 - Daniel Vassallo
@Daniel 看起来,如果我们测试一个属性(如 window.foo)而不是仅仅是一个变量(foo),那么抛出错误的问题似乎就不存在了。在这种情况下,较长的形式 (typeof window.foo != "undefined" && window.foo !== null) 相当于较短的形式 (window.foo != null),对吗? - Šime Vidas
@Šime: 是的,没错。undefinednull都是虚假的,而!=操作符会进行类型强制转换。因此那样做也可以...但你只能使用window.propertyName来访问全局命名空间中的变量。如果你在一个函数内有一个局部变量,那就会变得更加复杂。 - Daniel Vassallo

2
变量实际上可以保存值undefined,如果一个变量从未被赋值,那么这就是默认值。因此,如果使用var声明变量或通过赋值给变量,则foo != null将起作用,但如果没有,您将获得ReferenceError。因此,这两个代码片段是不等价的
如果您可以确定foo已声明,那么这比您原来的第二个代码片段更安全且易于理解,假设代码中没有类似undefined = 42的内容:
if(foo !== undefined && foo !== null) { }

所以,如果foo已经被声明(例如在var foo;中),那么我的两个代码片段是等价的。但是如果foo没有被声明,这两个代码片段就不同了,因为第二个代码片段会抛出一个错误。正确吗? - Šime Vidas
据我所知,是的。我仍然认为原始片段更好,因为它更清楚它所做的事情。引用Douglas Crockford的《JavaScript: The Good Parts》中的话:“当操作数是相同类型时,邪恶的双胞胎会做正确的事情,但如果它们是不同类型的,则会尝试强制转换值。他们这样做的规则是复杂和难以记忆的。” - PleaseStand
是的,第一个片段是正确的方法。我以为我可以简化那个检查(因为在JavaScript中null == undefined),但事实证明我不能这样做。 - Šime Vidas

2

一个简单的实验可以回答这个问题:

if( foo != null ) {
   alert('foo not null');
}

上述示例在许多浏览器中会产生JavaScript错误:"ReferenceError: Can't find variable: foo"。这是因为我们使用了一个未在当前作用域中声明为参数或var的变量。
另一方面,typeof运算符对于未定义的变量进行了明确的适配——它返回'undefined',因此:
if( typeof foo != 'undefined') {
    alert('foo is not defined');
}

正如预期的那样工作。

所以答案是“不”——它们不是同一件事——尽管在某些JavaScript环境中,它们可能表现出相同的方式,在其他环境中,当foo未定义时,您的第二个形式将产生错误。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接