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)?
CoffeeScript is a programming language that compiles to JavaScript. It adds syntactic sugar inspired by Ruby, Python, and Haskell in an effort to enhance JavaScript's brevity and readability. Specific additional features include list comprehension and destructuring assignment.
Single-line Comments Whenever we want to comment a single line in CoffeeScript, we just need to place a hash tag before it as shown below. Every single line that follows a hash tag (#) is considered as a comment by the CoffeeScript compiler and it compiles the rest of the code in the given file except the comments.
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 ''
.
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