SlightlyLoony
Tera Contributor

find_real_file.pngNot long ago I helped someone troubleshoot their script, which had the same problem as the sample script below. I'm more than old enough to have a glass of wine, but the script below says I'm to get a glass of milk. Can you spot the problem, and can you explain what's going on?


var person = {};
person.age = 125;
person.name = 'Slightly Loony';

if (person & person.age >= 21)
gs.log('Give him a glass of wine!');
else
if (person)
gs.log('Give him a glass of milk!');
else
gs.log('Houston, we have a problem!');


The problem is in the first if statement — the first operator should be a double ampersand (&&), not a single. Make that change and it all works as expected. But why? What's going on here? Isn't the double ampersand just a slightly different form of the same logical operator indicated by the single ampersand?

Well, no. Not at all. The double ampersand and single ampersand are actually very different.

The single ampersand is a numeric operator. Its use forces a coercion of the expressions on both sides to a number. The left side ("person") is an object, and coercing an object to a number results in NaN (not a number). The right side ("person.age >= 21") is a logical expression resulting in a boolean value of true, and coercing that to a number results in a 0. The ampersand operator then does a bit-by-bit numeric "and" operation on NaN and 0, and the result of this (by definition) is 0. The if statement then coerces the 0 to a logical value (false), so the else clause is executed. Whew! Make sense?

Now suppose you replace that single ampersand with a double ampersand. What's different?

First, the double ampersand is a logical operator, so using it forces the expressions on both sides to coerce to a boolean value. The left side ("person") is still an object, and coercing an object to a boolean value results in true. The right side ("person.age >= 21") is still a logical expression resulting in a boolean value of true, The double ampersand operator then does a logical "and" with a result of true — the result we really wanted in the first place.

There's an additional special feature of the double ampersand operator (and also of the double vertical bar operator "||") that's worth understanding well. These operators always evaluate from left to right, and they always stop evaluating if the results can be computed with no further evaluation (this is often called "short-circuit evaluation"). This is very useful in our example script, where the left side is basically testing for the existence of the person object, and then the right side is testing a property on that object. If person was a null for some reason, the left side of the expression would evaluate as a false (because coercing null to a boolean results in false). In this case, with the double ampersand operator, no matter what the value of the right side was the result would be false (because false logical and anything is false) — so the right side never gets evaluated at all. This is a good thing, because if it did try to evaluate the right side when person was null, we'd have an exception thrown.

So for this kind of work, it's double or nothing!

1 Comment