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
compiles to
and other times it just compiles to
The two are equivalent, because
x != null
will befalse
whenx
is eithernull
orundefined
. Sox != null
is a more compact way of expressing(x !== undefined && x !== null)
. The reason thetypeof
compilation occurs is that the compiler thinksx
may not have been defined at all, in which case doing an equality test would triggerReferenceError: x is not defined
.In your particular case,
test.test
may have the valueundefined
, but you can't get aReferenceError
by referring to an undefined property on an existing object, so the compiler opts for the shorter output.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:This JavaScript:
actually does check if the
foo
property ofa
is neitherundefined
nornull
. Note thata.foo?
is translated to JavaScript that uses!= null
rather than!== null
. The conversions that!=
does means that both of these are true:A plain
a?
becomes this JavaScript:because there are three conditions to check:
a
in scope anywhere?a
have a value ofundefined
?a
have a value ofnull
?The first condition is important as just saying
a != null
will trigger a ReferenceError if there is noa
in scope but sayingtypeof a === 'undefined'
won't. Thetypeof
check also takes care of thea === undefined
condition in 2. Then we can finish it off with a stricta !== 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:As far as your comment on the deleted answer is concerned,
if(a.foo)
is perfectly valid syntax if you complete theif
statement:However,
if(a.foo)
andif(a.foo?)
differ in how they handle0
,false
, and''
.