2

var obj, method;

obj = {
  go: function() { console.log(this); }
};

(method = obj.go)()

NOTE: Fyodor's first comment to his answer is what helped me the most. As the topic suggests, this was more about the parentheses than this.

In the last line, what I understand is that the parentheses will force the code inside to run first, so method takes the value of the go property, which is a function.

The () then calls that function, which logs window to the console because it wasn't called as a method.

If instead of (method = obj.go)(), you do method = obj.go(), it will first run the go function, and method will take the value returned by it. Since go returns nothing, it will be undefined. The value printed by go will be obj.

What I don't understand is, why if I do (obj.go)() the this printed is obj and not window?

Considering how the other code works, I expected this code to work kind of like this: obj.go is evaluated first inside the parentheses and then the function is run as an IIFE (function() { console.log(this); })(). So since the function isn't called as a method of obj, the this defaults to window.

SRCP
  • 204
  • 2
  • 9
  • Possible duplicate of [How does the "this" keyword work?](https://stackoverflow.com/questions/3127429/how-does-the-this-keyword-work) – Dexygen May 17 '19 at 23:15

1 Answers1

4

(method = obj.go)() evaluated in two steps.

  1. method = obj.go is evaluated and method var become equal to function go of object obj. Functions in JavaScript can be called as methods or as functions, so in general it doen't metter how you;ve defined function go.

  2. Then method() is called. As you didn't provided value for this (either by calling method function as method of some object or using bind or call it is called with this set to global object (in non strict mode) or to undefined (in strict mode)

When you call obj.go() this is set equal to obj (it is similar to use obj.go.call(obj) or method.call(obj)). If you call just method() this is equal to global object (similar to call obj.go.call(window))

EDIT

And to get obj as this with your example you can do such way

(method = obj.go.bind(obj))()

In this way you not only assign go function to variable method but create binding to specific this equal to obj

Good reading about function invocation and this in JavaScript

connexo
  • 41,035
  • 12
  • 60
  • 87
Fyodor
  • 7,344
  • 1
  • 20
  • 30
  • I understand all of this. I understand why `this` is what it is in all of the cases you mentioned. What I don't understand is why is `(obj.go)()` the same as `obj.go()`, but `(method = obj.go)()` is not the same as `method = obj.go()`. Why are the parentheses ignored in `(obj.go)()`? – SRCP May 17 '19 at 23:20
  • 1
    Parentheses like in many other languages control order of code execution. So for `(obj.go)()` internals of parentheses is evaluated first. It evaluated to `obj.go` as inside parentheses there is nothing to evaluate. Then `obj.go()` is called. When `(method = obj.go)()` is used there is `method = obj.go` inside parenthese, so here is something to evaluate. After evaluation `method` becomes equal to `go` method of `obj` and on second step just `method()` is called – Fyodor May 17 '19 at 23:24
  • It is simply down to the relative precedence of . () and = – James Gaunt May 17 '19 at 23:26
  • Thank you @Fyodor. I understand now. If I could mark this particular comment as the answer I would, since it's what clarifies my specific doubt. So I'll just mark the whole thing. – SRCP May 17 '19 at 23:27