Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I use the CoffeeScript existential operator to check some object properties for undefined?

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)?

like image 857
Przemek Avatar asked Apr 03 '12 09:04

Przemek


People also ask

What is CoffeeScript used for?

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.

How to comment in CoffeeScript?

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.


2 Answers

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.

like image 78
Trevor Burnham Avatar answered Nov 12 '22 17:11

Trevor Burnham


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:

  1. Is there an a in scope anywhere?
  2. Does a have a value of undefined?
  3. Does 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 ''.

like image 29
mu is too short Avatar answered Nov 12 '22 19:11

mu is too short