views:

105

answers:

6

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?

+10  A: 

The JavaScript operator || is defined to return the first value that evaluates to true or the rightmost value, if neither of the values are true 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
+2  A: 

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
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
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
+3  A: 

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
A: 

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
Watch that "anything non-zero" definition. `false`, `undefined`, and `""` are all non-zero, but are not considered truthy.
Matchu
@Matchu thanks, that's my perl background showing through. :( Fixed.
Andy Mortimer
+1  A: 

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
+8  A: 

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