30

我想使用 CoffeeScript 存在运算符来检查一些对象属性是否未定义。但是,我遇到了一个小问题。

像这样的代码:

console.log test if test?

编译为:

if (typeof test !== "undefined" && test !== null) console.log(test);

这是我希望看到的行为。但是,当我尝试对对象属性使用它时,如下所示:

console.log test.test if test.test?

我得到类似的东西:

if (test.test != null) console.log(test.test);

这根本不像是对未定义的检查。我可以实现与将其用于对象相同的 (1:1) 行为的唯一方法是使用更大的检查:

console.log test.test if typeof test.test != "undefined" and test.test != null

问题是——我做错了吗?或者编译后的代码是否足以检查属性的存在(带有类型转换的空检查)?

4

3 回答 3

54

这是与存在运算符混淆的常见点:有时

x?

编译为

typeof test !== "undefined" && test !== null

有时它只是编译为

x != null

两者是等价的,因为x != nullwill be falsewhen xis either nullor undefinedx != null更紧凑的表达方式也是如此(x !== undefined && x !== null)。发生编译的原因是typeof编译器认为x可能根本没有定义,在这种情况下进行相等测试会触发ReferenceError: x is not defined.

在您的特定情况下,test.test可能具有 value undefined,但您无法ReferenceError通过引用现有对象上的未定义属性来获得 a ,因此编译器选择较短的输出。

于 2012-04-03T14:32:42.793 回答
20

这个JavaScript:

a.foo != null

实际上确实检查了 is 的foo属性a是否为既不是undefined也不是null。请注意,它a.foo?被转换为使用!= null而不是!== null. 确实的转换!=意味着这两个都是真的:

null == null
undefined == null

一个普通的a?变成这个 JavaScript:

typeof a !== "undefined" && a !== null

因为要检查三个条件:

  1. 在任何地方都有a范围吗?
  2. a有值吗undefined
  3. a有值吗null

第一个条件很重要,因为a != null如果没有a在范围内但说不会触发,就会触发 ReferenceError typeof a === 'undefined'typeof检查还处理2中的a === undefined条件。然后我们可以通过严格的测试来完成它,因为它可以处理3而没有不必要的性能损失(注意:并且由于隐式转换而慢于并且由于)。a !== null!=!===!=====

稍微阅读一下什么!=!==做什么可能会有所收获:

MDN:比较运算符


就您对已删除答案的评论而言,如果您完成以下语句,if(a.foo)则语法完全有效:if

if(a.foo)
    do_interesting_things()
# or
do_interesting_things() if(a.foo)

但是,它们在处理、if(a.foo)和的方式上有所不同。if(a.foo?)0false''

于 2013-11-15T21:02:25.137 回答
4

胡乱猜测; 你试过console.log test.test if test?.test?吗?

刚刚用 测试了它coffee -p -e 'console.log test.test if test?.test?',它编译为:

(功能() {

if ((typeof test !== "undefined" && test !== null ? test.test : void 0) != null) { console.log(test.test); }

}).call(this);

于 2012-04-03T10:40:10.983 回答