Existential operator ?
can be used in three useful ways in CoffeeScript.
Checking the existence of a variable
In JavaScript there is no built-in way of checking the existence of a variable.
You can try testing the existence with if(variable){...}
but it won’t work in these cases:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
The correct way to test if variable was both declared and initialized:
1 2 3 |
|
You may be tempted to use direct comparison with undefined
:
1
|
|
But this is asking for trouble because in EcmaScript 3 (all older browsers, such as IE 6-8) undefined
can be overwritten:
1 2 3 4 5 |
|
All ES5 compatible browsers have undefined
immutable, i.e. it can’t be changed, but it’s better to play it safe.
CoffeeScript has a syntactic shortcut for testing existence:
1 2 |
|
This code will be transpiled to:
1 2 3 |
|
Conditional assignment
What if you want to initialize a variable only if it has not been already initialized? In JavaScript you’d usually do something like:
1 2 3 4 5 6 |
|
This technique caches the result of an expensive computation or database query in a variable.
In above example, all subsequent getUserLocale
function calls will not query the database.
The important part is comparing with null
using ==
, rather than ===
, because ==
will evaluate to true
if variable is either undefined
or null
.
Such cache on first call pattern is widely used in many programming languages, but CoffeeScript has a special syntax for it:
1 2 |
|
?=
is the operator that performs conditional assignment.
This will be transpiled to roughly the same JS as above, using ternary operator:
1 2 3 |
|
What if you try to conditionally assign an undeclared variable? If you try this:
1 2 |
|
This will result in a compile-time error:
the variable "abc" can't be assigned with ?= because it has not been declared before
.
This compile-time checking is very helpful, because it prevents a ReferenceError
at run time.
If you know Ruby, ||=
is the same thing there.
Safe property / function chaining
Chaining function calls is a great way to write terse yet fluent code. A good example is working with jQuery:
1
|
|
This is made possible because these jQuery functions return a reference to this
.
But what if one of the function returns null
or undefined
?
1
|
|
If current user’s address is null
or undefined
, the .zip
property call will result in TypeError
.
A simple but ugly solution would be to use a lot of if
checks:
1 2 3 4 5 |
|
But this can quickly get out of hand with deep nesting.
CoffeeScript has a safe way of accessing long property chains using ?.
variant of existential operator:
1
|
|
This will either soak up the null
or undefined
references and safely return undefined
or
return the final property value. In our case the generated code looks like this:
1 2 3 |
|
What is this weird void 0
thing? This is to fight the pre AS5 undefined
mutability I referred to earlier.
JavaScript defines void as a unary operator that returns undefined
for any argument. In other words, CoffeeScript compiler uses a set of nested ternary operators to safely return either last property value or undefined
with void 0
.
Calling a function safely works similarly:
1
|
|
This transpiles to:
1 2 3 |
|
Key thing to take away here is that CoffeeScript first tests that callable function is defined and is a function.
It does this using typeof bla === 'function'
. The function is called only if it is defined.
Safe function invocation can be chained as well with other function or property calls:
1
|
|
This transpiles to:
1 2 3 4 5 6 |
|
Drawing analogy with Ruby-on-Rails ActiveSupport, the safe chaining can be seen as try method.
Conclusion:
CoffeeScript existential operator is a useful tool to cut down the verbosity of JavaScript when dealing with existence and null checks. It also can be used to shield inexperienced JavaScript developers from JavaScript bad parts.