# Using Logical Operators To Perform Ternary Operations In Javascript

Posted November 18, 2009 at 10:13 AM by Ben Nadel

Tags: Javascript / DHTML

Yesterday on Twitter, Cody Lindley pointed out that logical operators in Javascript (&& and ||) don't simply return True or False - they return specific operands used in the logical statement. While I have leveraged this concept in the past with statements like this:

• // Logical OR in assignment.
• var options = (options || defaultOptions);
•
• // Logical AND in testing.
• if (window.console && window.console.log){ .. }

... it was still hard for me to wrap my head fully around what the logical operators were really doing. If you look at the Mozilla Development Center documentation on logical operators, you will see that not only is the statement being evaulated for its truth, but one of the operands is returned based on that truth, even if the returned operand is NOT true. To help understand this, you have to stop thinking in terms of individual operand truths and concentrate on the statement-level truth (regardless of the individual values).

Thinking this way helped me clarify the situation in my mind (pseudo code):

UPDATE: This is not quite accurate; (a && b) retuns "a" only if "a" can be converted to false.

• // Logical AND. ------
•
• if (a && b){
• return( b );
• } else {
• return( a );
• }
•
• // Logical OR. ------
•
• if (a){
• return( a );
• } else {
• return( b );
• }

When you start to look at it this way, you think less about what values "a" and "b" contain and more just about how the AND / OR statements will be evaluated.

Even with this mentality, I still felt a bit fuzzy on how things were really working. As such, I needed an exercise that would force it into my brain. That's when I came up with the fun idea of duplicating the ternary operator in Javascript using logical operators. Here's what I came up with:

UPDATE: This does not quite work; will not return proper value if ifTrue is a falsey.

• <script type="text/javascript">
•
• // This method will use a simple tertiary operator to
• // gather the description information based on the name.
•
• var easyIIF = function( girl, ifTrue, ifFalse ){
• return(
• ((girl == "Tricia") ? ifTrue : ifFalse)
• );
• };
•
•
• // This method will use a combination of logical operators to
• // gather the description information based on the name.
•
• var hardIIF = function( girl, ifTrue, ifFalse ){
• return(
• ((((girl == "Tricia") && ifTrue) || ifTrue) || ifFalse)
• );
• };
•
•
• // ------------------------------------------------------ //
• // ------------------------------------------------------ //
•
•
• // Set the name of the girl.
• var girl = "Tricia";
•
• // Output using easy tertiary operator.
• document.write(
• easyIIF( girl, "Hot", "Nice" ) +
• "<br />"
• );
•
• // Output using complex logical operators.
• document.write(
• hardIIF( girl, "Hot", "Nice" ) +
• "<br />"
• );
•
• </script>

What I created above is two different IIF() style methods that perform a ternary operation of sorts; the first one, easyIIF() used the actual ternary operator while the second one, hardIIF(), uses a combination of logical operators to duplicate the same functionality. When we run the above code, we get the following output:

Hot
Hot

This is pretty fascinating stuff... and a bit terrifying; using logical operators to perform more than simple boolean evaluation is nowhere near readable and requires the programmer to have an exhaustive understanding of how logical operators work. I wrote this post as an exercise - not to recommend that people use this approach (except in the most commonly understood use-cases).

### Looking For a New Job?

25% of job board revenue is donated to Kiva. Loans that change lives - Find out more »

Nov 18, 2009 at 10:25 AM // reply »

The 'fuzziness' was in my head too... and this cleared it! Thank you :)

Nov 18, 2009 at 10:29 AM // reply »

@Guganeshan.T,

Ha ha, sweeet.

Nov 18, 2009 at 10:31 AM // reply »

That is interesting stuff. I sure hope, though, that I never have to work on code where someone decided to substitute that approach for ternary operators! It's just not at all readable to me, and would be easy for me to get outputs flipped in my mind as I'm working through the logic. You should burn this blog post immediately. lol

Nov 18, 2009 at 10:33 AM // reply »

@Doug,

Right?!? Even after writing it, I have to remind myself what it's doing. It's all about the short-circuit evaluation on the || :)

Nov 18, 2009 at 11:03 AM // reply »

hi, I just thought "huh?" but then when I viewed the script closely, I became gradually clear what you mean ^ ^ is not at easy to understand, I really must admit ^ ^

Nov 18, 2009 at 11:05 AM // reply »

I've already been doing the logical OR ( var options = (options || defaultOptions); ) and always felt like I was cheating or doing something I shouldn't be doing.

Nov 18, 2009 at 11:07 AM // reply »

Now that Ben & Cody blogged about it, I can sleep better at night.

Nov 18, 2009 at 11:08 AM // reply »

When || is encountered, if the preceding expression was truthy, evaluation stops and that truthy value is returned.

When && is encountered, if the preceding expression was falsy, evaluation stops and that falsy value is returned.

Otherwise, things continue getting evaluated.

A truthy value is anything that == true, like 12 or "foo" or true, while a falsy value is anything that == false, like 0 or '' or undefined.

Where this is great is when you need to "test your way" into a property. For example:
var log = window.console && console.log;

1) window.console: truthy
2) &&: the preceding thing wasn't falsy, so continue.
3) console.log: it's the last statement, so its value is returned.

If you just tried this and console didn't exist, you'd get some errors:
var log = console.log;

Also, this..
var result = something ? something : otherthing;

..can be more succinctly written as:
var result = something || otherthing;

And because logical || and && short-circuit, that means when evaluation stops, nothing afterwards gets evaluated..

Meaning that in this example, if something is truthy, somefunction() will never get executed:
var result = something || somefunction();

Now, if you've made the "logical" leap here.. you can see that logical || and && can also be used.. to conditionally execute functions.

This..
something || somefunction();

..is equivalent to:
if ( !something ) { somefunction(); }

And this..
something && somefunction();

..is equivalent to
if ( something ) { somefunction(); }

So now you know what this code does:
window.console && console.log( "i'm only logged if window.console exists!" );

Either way, the end goal should be to write more readable, maintainable code though.. so if it looks complicated to you while writing it, it'll probably be about 5x worse to someone reading it six months from now, you know, someone like you :)

Nov 18, 2009 at 11:11 AM // reply »

@Sophie,

Yeah, funky stuff right?

@Todd,

I think that's one of those common use-cases that we all use. There are going to be nuances of complexity. Like, I think, as you are saying, that:

var a = (b || c);

... is pretty common. But, what about:

var a = (b && c);

... this gets a bit more fuzzy in my head (especially if you think that "a" will now hold a boolean).

var logger = ((window.console && window.console.log) || window.alert);

... definitely complex, but you sort of get the idea of what's going on.

I guess you just have to treat each situation as a judgment on usability and readability.

Nov 18, 2009 at 11:14 AM // reply »

@Cowboy,

Ha ha, we both used the console.log example at the same time :) Really good comment.

Nov 18, 2009 at 11:22 AM // reply »

@Ben, this is a perfect example of where *not* to use logical && and ||:

var logger = ((window.console && window.console.log) || window.alert);

What if console.log returns undefined? Then it logs AND alerts. I'm guessing that's not what you want.

This is probably what you want:
var logger = window.console ? console.log : alert;

Also, as an aside, note that you can't reference console.log in this way in all browsers. You should actually do:

var logger = window.console ? function(){ console.log.apply( console, arguments ); } : alert;

.. but that's why I've created a cross-browser console.log debugging wrapper:
http://benalman.com/projects/javascript-debug-console-log/

Nov 18, 2009 at 11:30 AM // reply »

@Cowboy,

I wasn't necessarily saying that you should do that - I was just pointing out that sometimes the complexity of a statement is made somewhat clear based on the items being referenced.

But, I am not sure what you are saying referring the undefined value? If console.log returns undefined, then the first statement would become false, and hence, window.alert would be returned.

I tested this in Internet Explorer, which doesn't have console.log and it went to the alert. Even if it's only partially defined:

window.console = {};
var logger = ((window.console && window.console.log) || window.alert);

... IE still defers to window.alert.

I am not sure what you mean. Also, I am not sure how it can both "logs AND alerts" - can you explain that further? Wouldn't that require some sort of concatenation of functionality?

Nov 18, 2009 at 11:33 AM // reply »

@Cowboy,

Your cross-browser logger looks badass. I'll have to take a close look at that. Thanks for posting it!

Nov 18, 2009 at 11:38 AM // reply »

I listed out a few examples of these in my jQuery Anti-Patterns talk. (They're a good thing, in my opinion; and can save quite a few bytes).

http://paulirish.com/perf/ <== Slide 54 of jQuery AntiPatterns slides
http://gyazo.com/8893db96d6d18b90b2a2ac150f4dd6cd.png <== Screenshot of that slide

It's just important to commment so noobs know what the heck you're doing. It's not the easiest code to understand. :)

Nov 18, 2009 at 11:41 AM // reply »

@Ben,

Sorry for the confusion.. the problem would be if you were actually invoking the function like:

var value = "foo";
window.console && console.log( value ) || alert( value );

In that case it would both log and alert, since even though console.log exists, when it's invoked it returns undefined, which is falsy.

Either way, a ternary removes all ambiguity:
window.console ? console.log( value ) : alert( value );

Still, you can't reference console.log like that win Webkit, it'll assplode all over the place.

Nov 18, 2009 at 11:46 AM // reply »

@Cowboy,

Ahhh, gotcha - sorry for the misunderstanding. I hate when Webkit assplodes... no one wants to start their day off that way :)

@Paul,

I'll take a look; sounds like maybe a good lead into one of your anti-pattern segments on YayQuery ;)

Nov 18, 2009 at 11:47 AM // reply »

Nice post Ben. I think it's okay to use basic stuff like:

function runFn(fn) {
return fn && typeof fn === 'function' && fn();
}

It may not seem readable to a JS beginner, but frankly, I write code assuming that another developer reading it will be proficient in the area. For me, a&&b&&b() is more readable than:

if(a){if(b){b()}}

Another interesting aspect of this topic is operator precedence and associativity, I discussed both in this post: http://james.padolsey.com/javascript/express-yourself/

E.g.

Does "a&&b||c" really mean "a&&(b||c)" or "(a&&b)||c" ... They are both very different. In this case, since &&'s precedence is higher than ||, it would be: "(a&&b)||c".

It's also interesting to note that expressions with multiple operators will sometimes be processed from right-to-left instead of the conventional left-to-right. For example, the ternary operator (a?b:c), if encountered more than once in a single expression, will evaluate from right-to-left:

a ? b : c ? d : e

is the same as:

a ? b : (c ? d : e)

but not the same as:

(a ? b : c) ? d : e

This is actually quite important -- it can cause a lot of confusion sometimes.

Nov 18, 2009 at 11:49 AM // reply »

Another example (that Paul and I have already discussed) of where function invocation can be an issue with logical || and && is in the slide he just mentioned:

data = window.JSON && JSON.parse(data) || eval('('+data+')');

If window.JSON exists, JSON.parse(data) is called.. but what if the initial data is "0"? That's valid JSON, and when parsed returns 0.. which is falsy. So at that point, eval('('+data+')') is actually called even though the JSON has already successfully been parsed.

Why not use:
data = window.JSON ? JSON.parse(data) : eval('('+data+')');

Well, if JSON.parse doesn't exist, you'll get an error. But you'd actually get that same error in the initial code.

So why not use:
data = (window.JSON && JSON.parse) ? JSON.parse(data) : eval('('+data+')');

It's the best of both worlds, logical && and a ternary!

Nov 18, 2009 at 12:01 PM // reply »

@James,

Case in point why I wake up happy every day that I have the option to litter my code with parenthesis - zero confusion on order of operations.

@Cowboy,

I think I vaguely remember Paul talking about that in his jQuery Performance talk. Maybe it was different (haven't looked at the slide yet), but I remember him talking about something where a result of zero would cause an issue.

I like your last example - to me, the combination of ternary and logical seems like the most clear.

Nov 18, 2009 at 12:04 PM // reply »

With the ternary-ish trick, you can force the first branch to always return true (and therefore always skip the second) regardless of what the first branch's expression evaluates to:

(exprTest && !(exprTestTrue && false)) || exprTestFalse;

ternary equivalent:
exprTest ? exprTestTrue : exprTestFalse;

Nov 18, 2009 at 12:19 PM // reply »

heh - you can take advantage of string truthiness and make it even shorter (and more unreadable) with this:

exprTest && (exprTestTrue || ' ') || exprTestFalse;

Nov 18, 2009 at 12:21 PM // reply »

@Jeremy,

Nov 18, 2009 at 12:51 PM // reply »

This exercise (and the resulting conversation) is one of the cool but frustrating things about programming to me.

It's cool to be able to write code to do things like you're discussing here: sometimes you can wrap up something that took 10-15 lines and compress it to 1-2 lines. The frustrating part is realizing that after you do that, no one else is going to be able to understand it, and if anything ever goes wrong with that part of the code, people are going to track you down to fix it ...

Nov 18, 2009 at 12:57 PM // reply »

OK - last one, but this is too hot not to share (worked in all my tests):

exprTest && exprTestTrue|1 || exprTestFalse;

bitwise ops FTW!

Nov 18, 2009 at 1:29 PM // reply »

David Gault just pointed out a typo in my example - easyIIF() was called twice; the second one should have been hardIIF(). The result is the same.

@Dave,

I hear what you're saying. I would err on the side of readability, when in doubt.

@Jeremy,

Bit-wise operations make my brain hurt - you are a mad scientist.

Nov 18, 2009 at 1:36 PM // reply »

Hold on.... I'm thinking this doesn't work now (specifically my example). If the ifTrue value is false. Working on it now.

Nov 18, 2009 at 3:09 PM // reply »

Regardless of the good conversation we've had here, I put some updates into the blog entry (in red) to signify some slight misunderstandings I had.

Nov 19, 2009 at 5:42 AM // reply »

hello ben. it's a funny script, but why do not create a rubric and give us a little more of these scripts, i think it would be fun to read ^ ^

Nov 19, 2009 at 10:12 AM // reply »

@Julius,

I am not sure what a rubric is? Can you explain further?

Nov 19, 2009 at 11:38 AM // reply »

In excess it certainly reduces readability, but the idea that the operators return a value is pretty foundational to some languages.

For instance, ruby doesn't have a ternary operator, instead you use the logical operators.

An example from a recent project was:

# username is the first command line argument if it exists

And another example where we emulate the ternary operator:

# format a URL for doing an http request where we need an int
URI.encode("reusetoken=#{reusetoken and 1 or 0}")

This certainly feels more readable than ?:

I was pretty disappointed to see the ternary operator added to CF9. I had hoped that the boolean operators would be uncrippled so that you'd no longer get the "X cannot be converted to a boolean" errors and instead get more JS like behavior. Perhaps in a later version.

Think:

#user.getEmail() or "Not Provided"#

vs

#len(user.getEmail()) ? user.getEmail() : "Not Provided"#

Nov 19, 2009 at 1:21 PM // reply »

@Elliott,

I personally like the ternary operator, but that's just a personal opinion.

Going back to the example you have regarding email, I made this just for you :) Hopefully it doesn't give you a heart attack:

<cffunction name="getFirstName">
<cfreturn "Ben" />
</cffunction>

<cffunction name="getLastName">
<cfreturn "" />
</cffunction>

<!--- Get the first name, or default to "Not Provided". --->
<cfset evaluate( "len( setVariable( 'firstName', getFirstName() ) ) || len( setVariable( 'firstName', 'Not Provided' ) )" ) />

<!--- Get the last name, or default to "Not Provided". --->
<cfset evaluate( "len( setVariable( 'lastName', getLastName() ) ) || len( setVariable( 'lastName', 'Not Provided' ) )" ) />

<!--- Output name values. --->
First Name: #firstName#<br />
Last Name: #lastName#

... When you run this, you get:

First Name: Ben
Last Name: Not Provided

... I feel so dirty now.

Nov 19, 2009 at 1:35 PM // reply »

@Ben

Hah! You should start a CF obfuscation contest.

Nov 19, 2009 at 1:37 PM // reply »

@Elliott,

Ha ha ha, it might be too rough on my stomach ;)

Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.

 Author Name: Author Email: Author Website: Comment: Supported HTML tags for formatting: bold   italic   code Remember my information Subscribe to comments Send me a copy of this comment
InVision App - Prototyping Made Beautiful With Prototyping Tools Recent Blog Comments
Mar 11, 2014 at 6:20 PM
Reading In File Data One Line At A Time Using ColdFusion's CFLoop Tag Or Java's LineNumberReader
Thanks Ben for you very interesting articles on handling large files. As I am not a programmer, I am quite insecure whether my issue is directly related to your description or not. My problem is, tha ... read »
Mar 11, 2014 at 12:21 PM
Compound Transclusion Prevented In AngularJS 1.2
Yeah this hit our team too and locked us as 1.1.5. It seemed like an irresponsible unilateral decision, but our graver concern is the future decisions the Angular team will make with other fundamenta ... read »
Mar 11, 2014 at 2:00 AM
ColdFusion, jQuery, And "AJAX" File Upload Demo
Mar 10, 2014 at 8:24 PM
Nested Views, Routing, And Deep Linking With AngularJS
@Steven, the action property is not something from AngularJS but rather part of the concept that Ben is describing in his blogpost here. it is a custom added property, which is read by the requestCo ... read »
Mar 10, 2014 at 2:03 PM
Nested Views, Routing, And Deep Linking With AngularJS
Where is the angular documentation for 'action:' it is not here: http://docs.angularjs.org/api/ngRoute/provider/ \$routeProvider Thanks. ... read »
Mar 10, 2014 at 12:06 PM
Using Track-By With ngRepeat In AngularJS 1.2
I was hoping that this will work with pagination using ng-repeat. My use case scenario is that I have an images object. images[0] = [im1,im2,im3] // First Page images[1] = [im4, im5, im6] // Second ... read »
Mar 9, 2014 at 6:11 PM
For Better Security Use HtmlEditFormat() In Conjunction With JSStringFormat() In ColdFusion
It looks like htmleditformat() will be deprecated in CF 11 https://wikidocs.adobe.com/wiki/display/coldfusionen/New +in+ColdFusion ... read »
Mar 9, 2014 at 10:55 AM
\$.stop() vs. \$.finish() In jQuery Animations
Nice feature! Thanks for sharing. :) Good for when you are making a 100% AJAX controlled site. ... read »