I would like to use the CoffeeScript existential operator to check some object properties for undefined. However, I encountered a little problem.
Code like this:
console.log test if test?
Compiles to:
if (typeof test !== "undefined" && test !== null) console.log(test);
Which is the behavior I would like to see. However, when I try using it against object properties, like this:
console.log test.test if test.test?
I get something like that:
if (test.test != null) console.log(test.test);
Which desn't look like a check against undefined at all. The only way I could have achieved the same (1:1) behavior as using it for objects was by using a larger check:
console.log test.test if typeof test.test != "undefined" and test.test != null
The question is - am I doing something wrong? Or is the compiled code what is enough to check for existence of a property (a null check with type conversion)?
This is a common point of confusion with the existential operator: Sometimes
x?
compiles to
typeof test !== "undefined" && test !== null
and other times it just compiles to
x != null
The two are equivalent, because x != null
will be false
when x
is either null
or undefined
. So x != null
is a more compact way of expressing (x !== undefined && x !== null)
. The reason the typeof
compilation occurs is that the compiler thinks x
may not have been defined at all, in which case doing an equality test would trigger ReferenceError: x is not defined
.
In your particular case, test.test
may have the value undefined
, but you can't get a ReferenceError
by referring to an undefined property on an existing object, so the compiler opts for the shorter output.
This JavaScript:
a.foo != null
actually does check if the foo
property of a
is neither undefined
nor null
. Note that a.foo?
is translated to JavaScript that uses != null
rather than !== null
. The conversions that !=
does means that both of these are true:
null == null
undefined == null
A plain a?
becomes this JavaScript:
typeof a !== "undefined" && a !== null
because there are three conditions to check:
a
in scope anywhere?a
have a value of undefined
?a
have a value of null
?The first condition is important as just saying a != null
will trigger a ReferenceError if there is no a
in scope but saying typeof a === 'undefined'
won't. The typeof
check also takes care of the a === undefined
condition in 2. Then we can finish it off with a strict a !== null
test as that takes care of 3 without the performance penalty of an unnecessary !=
(note: !=
and ==
are slower than !==
and ===
due to the implicit conversions).
A little reading on what !=
and !==
do might be fruitful:
MDN: Comparison Operators
As far as your comment on the deleted answer is concerned, if(a.foo)
is perfectly valid syntax if you complete the if
statement:
if(a.foo)
do_interesting_things()
# or
do_interesting_things() if(a.foo)
However, if(a.foo)
and if(a.foo?)
differ in how they handle 0
, false
, and ''
.
Wild guess; have you tried console.log test.test if test?.test?
?
Just tested it with coffee -p -e 'console.log test.test if test?.test?'
, which compiles to:
(function() {
if ((typeof test !== "undefined" && test !== null ? test.test : void 0) != null) { console.log(test.test); }
}).call(this);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With