permalink

25

Exploring JavaScript’s Logical OR Operator

In JavaScript, logical operators are used for boolean logic where a boolean value may be returned depending on the outcome of an expression. With the || (OR) operator, since values don't need to be explicitly true or false (they can be truthy or falsy), the operator can return non-boolean results when evaluated.

Introduction

To understand the || operator, let's first look at a fairly basic example. The logical OR operator may be used to provide a default value for a defined variable as follows:

var bar = false, 
     foobar = 5,
     foo = bar || foobar; // foo = 5

In this case, foo will only be assigned the value of foobar if bar is considered falsy. A falsy value could be considered being equal to 0, false, undefined, null, NaN or empty (e.g "").

This pattern might look familiar as if you've written jQuery plugins before or used $.extend(), you'll see it implemented when checking for an options object to either be specified or set to an explicit default value:

function( options ) { 
    options = $.extend({}, defaults, options || {}); 
} 

Some developers also like using the || operator to set explicit null values when handling falsy values in an application. This helps ensure that values are intentionally nullified:

var foo = bar || null;

Commonly, you're unlikely to want null values but when you do, there's a certain comfort in not having to wonder if it's a desired value or if it indeed should be a nullified property or variable.

You may also see developers opting for this approach to default-namespacing, where rather than opting for a two-line statement consisting of namespace = namespace || {} and populating the object later, this is all done at once as follows:

var namespace = namespace || {
    utils:{},
    core:{}
};

Behind The Scenes

Now, JavaScript variables aren't typed, so a variable may be assigned a value (e.g. a number), despite being assigned through boolean operators:

console.log(null || NaN || undefined || false || 0 || 10); 
// outputs: 10

What's happening here isn't quite magic—the expression is simply being lazily evaluated. The interpreter checks the value of the first part of the statement, null, establishes that it's falsy and continues moving forward until a falsy value isn't found (or if no truthy value is found, returning the last value). It's a neat trick that works in dynamic languages beyond just JavaScript, but won't work in static languages, where a type error will be thrown if you try the above.

If you're interesting in reading up more about the evaluation technique used in this example, check out short-circuit evaluation.

So, where is any of this useful? The OR operator can be applied to functions where we wish to provide a default value (as we've seen earlier) if falsy-ness is incurred as follows:

function foo( a, b ){
        a = a || 5;
        b = b || 6;
        console.log( 'Values:' + a + ',' +b );
}

Although, you're more likely to see a ternary to solve this problem in the wild, or perhaps something similar to this:

if(a && a === 5){
        // do something
}else{
        // do something else
}

You may be wondering why. In my opinion it comes down to two things:

Readability: Some developers feel that if/else is easier to read and it can certainly save time when you don't have to evaluate the expression in your mind while looking through code. I would argue that we still have to do the same with if/else, but it comes down to a matter of preference at the end of the day.

Performance: The developers I've discussed the OR operator with have had a perception that if statements had to be more performant than ||, however I believed they had to be at least equivalent performance-wise.

Performance Testing

With the aid of jsPerf, we can test out one example of OR vs IF to find out how they compare:

Performance testing: OR vs IF

var caseTrue = false;

function sum(){
        return 100 + 10;
}  

// test 1
caseTrue || sum();

// test 2
if(!caseTrue){
        sum();
}

Results

As you can tell by the results (http://jsperf.com/or-versus-if/2), both operators perform equally as well with WebKit (most versions of Chrome/Safari) and Opera. In Firefox (4,8) and IE 8 and 9, however, OR actually out-performs if which is very interesting.

That said, these numbers are also extremely high, the number of operations per second is exceeding 100 million, and whichever approach you end up using would probably not impact the performance of your application.

At the end of the day it's still going to come down to whether you feel one or more readable than the other (a discussion parallel with whether or not ternary operators should be used).

More Tricks

Now that we've looked at performance testing, there are a few other tricks that the logical operator can be used for. In the following example if the expression on the left evaluates to true, a positive equality message is logged whilst evaluating to false has the opposite effect.

var bar = 5;
bar == 5 && console.log('bar equals 5'); 
// outputs: bar equals 5

bar == 8 || console.log('bar does not equal 8'); 
// outputs: bar does not equal 8

And just for the curious:

bar == 5 || console.log('bar equals 5'); 
// evaluates to true

bar == 8 && console.log('bar does not equals 8'); 
// evaluates to false

The logical OR operator can also however be used in a number of other places:

('foo' || 'bar'); // returns foo

Although a specific falsy value hasn't been assigned to either side above, the first object is considered truthy in this case, which is why foo is returned. The second object would be returned if the first was falsy.

Extending the 'default value' concept slightly, it's possible to define functions that either execute specific methods defined within a namespace, or define those methods if they don't exist. This can be done a number of different ways (with optional type-checking), but a basic example could look like:

function helloWorld( fn ){
    (fn.method = fn.method || function() {
        console.log('foo');
    })();
}

helloWorld({}); // outputs: foo

//passing in an object with a method
helloworld({
        method:function(){
                console.log('boo');
        }
}); //outputs boo

The || operator could also be used in combination with a ternary to support:

  • Querying the DOM for an element if a reference we expect to be cached is falsy/undefined
  • Dynamically creating the element if the result of querying the DOM is that the element didn't exist and thus returned an empty result.
// bar, either undefined or a cached selection of $('#bar')
// var bar = $('#bar');
var bar;

// if bar isn't undefined/falsey, use bar, otherwise query the
// DOM for the div 'bar' so we can cache it in 'foo' if
// bar has a valid length (i.e isn't an empty collection)

// if bar doesn't exist in the global scope and isn't currently
// in the DOM, we'll dynamically create a div and set it's ID to
// 'bar' instead.

var foo = bar = bar && bar.length && bar ||
    (bar = $('#bar')).length ? bar :
    $('<div />', { id: 'bar' });

console.log(foo, bar);

 

You can try out the above code sample here:http://jsfiddle.net/dY5W9/6/

The above approach to solving this problem should typically not be used in production environments and is only shown for demonstration purposes. There are far simpler (and more readable) ways this problem can be solved.

Finally, here are some further experiments using the OR operator, just in case you're interested in how truthy/falsy/other values are evaluated:

true || true       // returns true
false || true      // returns true
true || false      // returns true
false || (5 === 6)  // returns false
"foo" || "bar"     // returns foo
false || "bar"     // returns bar
"foo" || false     // returns foo
(0 || 'bar'); // returns bar
(false || true || false || false); // true
(false || false || true); // true

Wrapping Up

That's it! Whilst || has many potential uses, always remember to factor in readability of your code when opting to use it. If you have any other gotchas, corrections or comments to share, feel free to leave them below and we'll get back to you. Happy coding.

25 Comments

  1. Addy,

    Great post, as usual. But why isn't your $.extend example set up like this:

    function( options ) {
    options = $.extend({}, defaults, options || {});
    }

    so that the properties of the third object overwrite any defaults?

  2. @webXL I scrolled down here to comment on that, too. .extend() can figure that out on its own. If your object doesn't have defaults, there's nothing to extend…just omit the entire line, no? Addy, I commend you on including the sentence "always remember to factor in readability of your code when opting to use it" without the use of expletives. This is all I was thinking about while reading the post…

    • @webXL @aaronlpeterson Thanks for pointing that out. I think it was just an oversight on our part as we only wrote this up this morning : – ). I've updated the post to use the (better) .extend() pattern you've mentioned.

      I think the sentence about avoiding some of the uses of the OR operator mentioned is critical for any post like this. There are hundreds of interesting "quirks" with the language that are useful to know, even if useful means knowing when *not* to use them :)

    • Thanks! I believe I corrected it earlier, but I've just flushed the site cache in case it hasn't showed up yet. With respect to that article, I've indeed read it before but couldn't for the life of me locate the link back to it again. Thanks for sharing!. I'll update the post with some references to it when I get a chance.

  3. Here's one I like:

    var fns = {
    ask: function( msg ) { console.log( msg + "?" ); },
    shout: function( msg ) { console.log( msg + "!" ); },
    default: function( msg ) { console.log( msg + "." ); }
    };
    function say( type, msg ) {
    ( fns[ type ] || fns.default )( msg );
    }

  4. You probably never want to do "a = a || 5;" when you're trying to establish a default value for a numeric parameter. If a===0, it'll get changed to 5 here.

    • I was thinking that too, but *might* still be useful if 0 is not a permissible value for a, and/or in a situation in which a is only being assigned programmatically (i.e. not by user input).

  5. Thanks for this article :)

    This technique is also useful with the RegExp.exec method. Look at this:

    var expr = /(w+).com/,
    str = "addyosmani.com",
    parts = expr.exec( str ) || [ "", "default value" ],
    domainName = parts[ 1 ];

    if( domainName )
    {
    // …
    }

    This'll execute the regular expression "expr" over the string "str". In case it match, exec method will return an array containing the full string and the match part (2 length array). In case it fails, it will returns null; the OR operator is useful now, allowing us to return a default array of values (2 length too). Then, in every case, we're using that array and we're getting the element which index is 1.
    The good part here is that the "parts" variable will always be an array. If we remove the OR trick, then it may return null in some case, and then the parts[1] could throw an error like "TypeError: Cannot read property '1' of null".

    Hope you'll like it :)

  6. Great article. Very informative and interesting…
    The second-to-last code snippet seems to have broken, though. The site displays it as 2 snippets, when I guess they're meant to be one?

  7. Great read! Was just wondering why this:

    var foo = bar = bar && bar.length && bar ||
    (bar = $('#bar')).length ? bar :
    $('<div />', { id: 'bar' });

    was not just this:

    var foo = bar = bar ||
    (bar = $('#bar')).length
    ? bar
    : $('<div />', { id: 'bar' });

    Am I missing something?

  8. Really useful stuff! ;) I like the simplicity of || and it is much more readable then lot of if/else statements… I see nice use of if in json callback responses, where I'm not sure how data will come or on few places I know I will get slightly different format.
    It's easy to check what I expect, what should be used and just move forward to not get into weird loop of IFs and problem with undefined variables ;)

    Thanks!

  9. Pingback: Exploring JavaScript’s Logical OR Operator | Fly mini

  10. For some reason, Safari and Chrome (so I assume all WebKit browsers) are throwing errors with the following:
    var foo = bar || null;

    Saying “Can’t find variable: bar”

    Is this something new? I don’t recall this happening in the past.

  11. Hi Addy,

    I recommend
    if (null == x) x = default;
    which only assigns default to x when x is null or undefined,
    rather than
    x = x || default;

    I think using the OR operator to shortcut function args has become a bit of an anti-patterns at this stage, with the result that “falsy” values like 0 and false can mysteriously disappear. See https://github.com/BorisMoore/jsrender/issues/31 for a real example in the wild of this in the wild.

    Or a simpler example:

    /** Don’t render blank text. Oops: doesn’t render 0 as well. */
    function render( text ) {
    text = text || “”;
    // … do something with text
    return text ? _compile(text || “”) : “”;
    }

    function _compile(text) {
    return “” + text + “”;
    }

    which fails for numeric input:

    render(0) returns “” instead of “0″
    render(false) returns “” instead of “false”

    where what you really want is:

    /** Don’t render blank, null, NaN, or undefined text but works for 0 and false. */
    function fixed_render( text ) {
    if (null == text) text = “”;
    // … do something with text
    return null != text ? _compile(text) : “”;
    }

    Which is one reason I pushed for something like the Existential Operator ?= in Coffeescript some time back, so you could do

    render = (text) ->
    text ?= “”;
    _compile(text) if text?

    or

    render = (text = “”) ->
    _compile(text)

    ->> Josh W <<-

  12. Pingback: Zebrane linki z Chrome w domu (wg. mnie ciekawe) « Wiadomości o technologiach IT

  13. I also like to use this logical operator trick for caching properties or jQuery selectors inside a class or object:

    var elm = this.elm || (this.elm = document.body);

    console.log(elm.nodeName);

  14. Hi, great job !

    I have I question. Why javascript is not returning a boolean value when using boolean operators during an initialization?
    For instance, with the following code :
    var type = null;
    var result = type || ‘n/a’;

    I don’t understand why result contains ‘n/a’ instead of true (logical evaluation of the string ‘n/a’)?
    For instance, in php, the result is TRUE and I think it’s more logical for a semantic point of view

Leave a Reply

Required fields are marked *.