6

I want to understand why the parenthesis around o.method in the expression

(o.method)()

are ignored and so it's behaving equally to o.method(), with execution context of method referencing o. I was expecting it to behave similarly to (o.method || true)(), where execution context inside method references global object.

If I evaluate (o.method) on its own, it returns reference to a standalone function not bound to any context. Simply rewriting it like this

var a = (o.method); a(); 

will have global context as expected. And I've just shortened the code by replacing a, and it produced different result.

Max Koretskyi
  • 101,079
  • 60
  • 333
  • 488
  • I know this doesn't answer the parentheses question, but you can use `o.method.call()` to nullify the context – Mulan Nov 01 '16 at 05:47
  • Also `true` is not a function – Mulan Nov 01 '16 at 05:48
  • @naomik, yeah, I know, thanks, for some reason this question repeatedly gets understood in terms of execution context, and not parsing. Didn't understand your comment about the `true` not being a function – Max Koretskyi Nov 01 '16 at 05:48
  • "o.method" just returns the function body. "Accessing a function without () will return the function definition" – Pavan Chandaka Nov 01 '16 at 05:49
  • @PAVANCHANDAKA queestion is, when `o.method` is called, `this` should have pointed to `window` and not to current object – Rajesh Nov 01 '16 at 05:50
  • @Maximus Just a curious question, Why do you expect it to have a global context? `setTimeout` or `setInterval` callbacks are pushed in event loop and are processed from there. IIFEs are executed as they are encountered. So should they not retain context? – Rajesh Nov 01 '16 at 05:54
  • @Rajesh, because just simply rewriting it like this `var a = (o.method); a();` will have global context. I've just shortened the code, and it produces different result. Are you sure it's parsed as IIFE? I was thinking that IIFE is relevant defining and calling a function, while it's defined somewhere before in my example – Max Koretskyi Nov 01 '16 at 06:04
  • I found this: http://stackoverflow.com/questions/32622383/javascript-function-call-expression-for-object-member-functions , which is kind of a duplicate, but I know there is a much better duplicate that I've seen before – Paul Nov 01 '16 at 06:12
  • @Rajesh, I don't think there's such thing as IIFE in the context of how interpreter parses expressions :). – Max Koretskyi Nov 01 '16 at 06:12

2 Answers2

12

I think it has to do with ES5 11.1.6:

11.1.6 The Grouping Operator # Ⓣ

The production PrimaryExpression : ( Expression ) is evaluated as follows:

  1. Return the result of evaluating Expression. This may be of type Reference.

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.

Let's see how function invocation is done in JS:

The key point is that o.method is a Reference (as defined by the spec):

A Reference is a resolved name binding. A Reference consists of three components, the base value, the referenced name and the Boolean valued strict reference flag.

So, o.method is not a Function YET; it is basically [[o, "method", false]]. When invoked with an argument list, o.method(), the reference value is taken by GetValue, then the method invocation proceeds (as described in 11.2.3).

When you do (o.method)(), (o.method) is still a Reference - GetValue has still not been applied to it (per the quoted 11.1.6). So nothing changes.

When you do (o.method || true)(), || will apply GetValue to the left side (per 11.11) and produce a function value - not a Reference any more. Thus, it cannot be evaluated as a method invocation, since the information about the base and referenced name (that was present in Reference) is lost.

Community
  • 1
  • 1
Amadan
  • 191,408
  • 23
  • 240
  • 301
  • thanks, right to the point. You put `o` as the `base value` here `[[o, "method", false]]`, so is it correct to assume that when you define a function `foo` in global context and then reference it the `base value` is set to `window`, as in `[[window, "foo", false]]`? – Max Koretskyi Nov 01 '16 at 06:16
  • @Maximus: Yes, that is my understanding as well. (Although I must admit I am a bit fuzzy on the "strictness reference flag", it is not relevant to this discussion.) – Amadan Nov 01 '16 at 06:17
  • great, thanks. Also is my understanding correct that, on high level, `GetValue` follows the pointer to a memory address and retrieves the bits and interprets them as a function? – Max Koretskyi Nov 01 '16 at 06:24
  • In more detail, `foo` is an [identifier](https://es5.github.io/#x11.1.2) that is resolved by [GetIdentifierReference](https://es5.github.io/#x10.2.2.1), walking up the environment chain until it hits the [global environment object](https://es5.github.io/#x10.2.3), which in the case of a browser environment is `window`. (Also, I figured out the strictness flag: it's the current strictness at the location where Reference is located, and, as I thought, is not relevant here.) – Amadan Nov 01 '16 at 06:27
  • As for GetValue, [pretty much](https://es5.github.io/#x8.7.1) - it resolves the reference and returns the value the reference points to. (Let's hope it's a function, or `o.method()` is in for a rude surprise.) – Amadan Nov 01 '16 at 06:29
  • Got it, appreciate your help! Good luck) – Max Koretskyi Nov 01 '16 at 07:01
  • Just rereading the answer, and I'm thinking what's in `a` in this statements `var a = (o.method); a();`? is it a reference or the function? it should be the reference, right? probably the _value_ is changed to global object, instead of `o` – Max Koretskyi Nov 01 '16 at 20:58
  • 1
    No, it's a function. References don't exist in JavaScript - they only exist in the specification, and possibly in implementation, but there is no such type in the language itself. The reference will have GetValue applied to it when `var a = ...` is resolved, per `VariableDeclaration : Identifier Initialiser` rule in [12.2](https://es5.github.io/#x12.2). Actually, pretty much every evaluation in the language will apply GetValue, except for `delete`, `typeof`, grouping parentheses and left hand side in assignments and declarations (maybe I'm leaving a couple out, but not many). – Amadan Nov 02 '16 at 00:18
  • thanks, sorry for additional questions, but I'm trying to get it right. You're saying that `a` is a function, so how come when we do `var b = a` we still have one function? I always thought that a variable sort of holds a reference to memory address where the actual value can be found (like pointers in `C`). Maybe I'm didn't understand what you were trying to say – Max Koretskyi Nov 02 '16 at 06:11
  • Different meanings of "reference". "Reference" I was talking about is the one defined by ECMAScript (`[[base, name, strictness]]`), a specification type that does not exist in the language; "reference" you are talking about is, as you say, what we normally assume we are assigning when we do `b = a` instead copying objects. They are not the same thing. `{foo: 7}.foo` is a Reference (`[[{foo: 7}, "foo", false]]`) but not a "reference" (as `7` is a primitive type); `(Array.prototype || true)` is a "reference" (points to an object) but not a Reference (as it has been resolved by GetValue). – Amadan Nov 02 '16 at 07:27
  • So yeah, `var b = a` will resolve `a` using GetValue, which means it stops being a Reference; but it will create a binding `b` that evaluates to the same exact value (not a clone of the value) as the binding `a`. If we change the value of `b`, the value of `a` changes accordingly. We say they "share a reference"; but this is an implementation detail. JS could also copy the value and then update every copy when one of them changes; this would be stupid and slow and stupid, but I think it would be compliant to the spec since it would evaluate the same way (without actually having "references"). – Amadan Nov 02 '16 at 07:35
  • I see, thanks a lot for the clarification! Appreciate) – Max Koretskyi Nov 02 '16 at 07:38
-3

This is called Method Invocation. When a function is stored as a property of an object, we call it a method. When a method is invoked, this is bound to that object. If an invocation expression contains a refinement (that is, a . dot expression or [subscript] expression), it is invoked as a method.

So in your case when you call o.method, this will refer to the object 'o'.

this will call to window object in case of function invocation.

Please refer : https://www.safaribooksonline.com/library/view/javascript-the-good/9780596517748/ch04s03.html

Majed
  • 53
  • 8