10

Lines 1-2 and 4-5 make sense in terms of the this returned. What am I missing about line 3? I thought it would return window similar to lines 4-5. Is there another pattern not in these 5 that could help demonstrate why?

foo = { bar : function () { return this } }

foo.bar() // ==> foo

(foo.bar)() // ==> foo / but why?

(foo.bar ? foo.bar : $.noop)() // ==> window

(foo.bar || 0)() // ==> window
AstroCB
  • 12,337
  • 20
  • 57
  • 73
TomFuertes
  • 7,150
  • 5
  • 35
  • 49
  • 1
    As I understand it, there is, between `(foo.bar)` and `foo.bar`(line 2) no difference. Its just inserting unnecessary brackets like ` 1 + 2 * 3 ` is the same as ` 1 + ( 2 * 3 ) ` – Dustin Hoffner Apr 11 '15 at 16:54

2 Answers2

9

The grouping operator does not destroy property references, which are provoking the method call.

This is explicitly mentioned in the spec:

NOTE: This algorithm does not apply GetValue to the result of evaluating Expression. The principal motivation for this is so that operators such as delete and typeof may be applied to parenthesised expressions.

In your lines 4 and 5, it's not the parenthesis but the operators (?: and ||) that de-reference the property and yield the "unbound" function.

adiga
  • 34,372
  • 9
  • 61
  • 83
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • 1
    Nice answer, there are actually common tricks to "get around" this, the most common I've seen is `(0,foo.bar)` to break the reference or cause an indirect call without adding a line. It gives rise to [an interesting example with `eval`](http://stackoverflow.com/questions/19357978/indirect-eval-call-in-strict-mode) too :) – Benjamin Gruenbaum Apr 11 '15 at 21:37
3

foo.bar here is an anonymous function.

It might make more sense if you split it up into different lines:

foo = {
    bar: function() {
        return this;
    }
}

So, when you call foo.bar, you're getting function() { return this; }. On line two, you call that function directly (foo.bar()), so it returns this, the instance of the object (foo).

On line three, you get the same result because you're not only asking for the anonymous function, but executing that function as well:

(foo.bar); // (function() { return this; }); A reference to the function
(foo.bar)(); // (function() { return this; })(); Actually calling the function

Because in the latter case, you're executing the function as you did in line two, the result is the same (foo).

In lines four and five, however, as Bergi said, the operators you use dereference them from the function, which leaves you with a Window object rather than foo.

AstroCB
  • 12,337
  • 20
  • 57
  • 73