23

I saw this construction in order to get the browser viewport width:

function () { return window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth; }

I understand the browser quirks involved. What I don't understand is why || returns the value. So I tried this alert(undefined || 0 || 3); and sure enough, it alerts 3. I find this bizarre, because I expect true or false. Could anyone explain what's going on?

Fletcher Moore
  • 13,558
  • 11
  • 40
  • 58

6 Answers6

32

The JavaScript operator || is defined to return the left value if it evaluates to a truthy value, otherwise the right value instead of returning true itself. That's just how it's defined in the spec.

I know it can be annoying at times, you might accidentally end up holding a reference to something you don't want to hold on to, but it also allows for the handy trick your example has. Everything has its pros and cons.

Matti Virkkunen
  • 63,558
  • 9
  • 127
  • 159
21

Take a look at the ECMAScript standards section 11.11 Binary Logical Operators

The production LogicalORExpression : LogicalORExpression || LogicalANDExpression is evaluated as follows:

1.Evaluate LogicalORExpression.

2.Call GetValue(Result(1)).

3.Call ToBoolean(Result(2)).

4.If Result(3) is true, return Result(2).

5.Evaluate LogicalANDExpression.

6.Call GetValue(Result(5)).

7.Return Result(6).

So it evaluates the boolean conversion of each operand, but returns the actual value of the operand.

If you want to know how Javascript converts values to a boolean, see section 9.2 ToBoolean

Paul Dixon
  • 295,876
  • 54
  • 310
  • 348
17

Don't think of it as "or". It's more like a flow-control device within an expression. The value of a || expression is the value of the first subexpression that's "truthy". Thus, the evaluation of the series of subexpressions stops at some point, as if

 expr1 || expr2 || expr3

were

 (function() {
   var rv = expr1;
   if (rv) return rv;
   rv = expr2;
   if (rv) return rv;
   return expr3;
 })()
Pointy
  • 405,095
  • 59
  • 585
  • 614
7

The OR function is a short-circuit OR evaluation - it returns the first element that is not false, or the last false element otherwise.

This is actually quite useful, so you can write expressions like

a = a || someValue;

Which is the same as

if (a==null)
  a = someValue;
mdma
  • 56,943
  • 12
  • 94
  • 128
  • 2
    It's not just "not null". The empty string and numeric zero are both treated as "false". The "undefined" pseudo-value is also treated as "false", though that's where things get a little wierder. – Pointy Jun 03 '10 at 13:45
  • edited: now use true and false as definitions. Looking at the ECMA standard, it converts each value to boolean for the test, via toBoolean but returns the value itself after testing. – mdma Jun 03 '10 at 16:11
3

It's just the way it is by design. ||, like && is a short-circuit operator, the expressions are evaluated in order, they stop after an expression meets the criteria and yield the result of the expression. The same is true of &&:

var  myObj  = { "Test": { "Foo":"Bar" } };
var  myObj2 = { "Foo": "Bar" };

alert(myObj.Test && myObj.Test.Foo); // will alert "Bar";
alert(myObj2.Test && myObj2.Test.Foo); // will alert undefined;
Andy E
  • 338,112
  • 86
  • 474
  • 445
1

Some values, such as zero, "" or undefined, are treated as false. Anything else is true, so the || operator just returns the first non-zero (ie true) value in the pair that it's given. This is useful for tricks like the code above, but I'm guessing it wasn't added to the language just to let you skip the odd if statement.

I suspect it may have originated as a performance tweak, since the higher-level languages (such as BASIC ... yes, maybe an odd definition of higher-level) used fixed constants for true and false -- often 0 and -1, or 0 and 1.

Andy Mortimer
  • 3,619
  • 20
  • 14
  • 2
    Watch that "anything non-zero" definition. `false`, `undefined`, and `""` are all non-zero, but are not considered truthy. – Matchu Jun 03 '10 at 13:43
  • @Matchu thanks, that's my perl background showing through. :( Fixed. – Andy Mortimer Jun 03 '10 at 14:08
  • 1
    I like to think of ||'s and &&'s behavior as 'the value of the argument that determined truthiness or falsiness is returned'. – Ian Durkan Aug 17 '13 at 20:33