1

I am learning Js. While reading YDKJS Series, I came through an example and struggling hard to figure it what is happening.

function foo() {
  console.log(this.a);
}

var a = 90;

var obj1 = {
  a: 1,
  foo: foo
};

var obj2 = {
  a: 2
};

(obj2.foo = obj1.foo)(); //90
obj2.foo(); //2

In this snippet, why (obj2.foo = obj1.foo)(); the foo's this variable is pointing to global object and in the next line, it is pointing to the obj2, i.e in which context the function was called. Can you tell me, what I am missing here. What is the correct role of the () in obj2.foo = obj1.foo. The same syntax is being used in IIFE. Can someone explain me?

Ele
  • 31,191
  • 6
  • 31
  • 67
Maninder
  • 15
  • 4
  • 3
    `obj2.foo = obj1.foo` *returns* whatever you've assigned. In this case, it returns a reference to the `foo` function but when you execute it, you don't have any context attached, thus it's the same as doing `foo()` - you get `this === window` – VLAZ Feb 04 '20 at 12:29
  • The parenthesis are used here only to distinguish `(obj2.foo = obj1.foo)()` from `obj2.foo = (obj1.foo())`. [They do not affect the the `this` value](https://stackoverflow.com/q/29580252/1048572). – Bergi Feb 04 '20 at 12:50

1 Answers1

0

It is not the same syntax. JavaScript does not distinguish between methods and functions as values, the distinction is purely in method call. The syntax receiver.method(...args) (if receiver.method is a non-arrow function) calls as method, i.e. it will set this to receiver during the call. (Equivalently, the syntax receiver[methodname](...args) will do the same.)

Any other function call syntax is just a function call, without affecting this. Specifically, (obj2.foo = obj1.foo) evaluates to just a function, that does not know what receiver it should be addressed to, and consequently this is the global object, and this.a the global variable a.

EDIT: Examples...

window.context = "global";
let foo = {
  context: "foo",
  fn: function() { console.log(this.context); },
  arrow: () => { console.log(this.context); },
}

console.log(this.context); // global object (`window` in browser, `global` in Node)
foo.fn(); // method call syntax; `this` is set to `foo`
foo["fn"](); // equivalent to the above; `this` is set to `foo`
foo.arrow(); // method call syntax but arrow, so doesn't matter; `this` is unchanged
let fnS;
fnS = foo.fn; fnS(); // no receiver, regular function call, `this` is unchanged
(fnS = foo.fn)() // equivalent to the previous one

Of these examples, only the foo.fn() and foo["fn"]() will set this to foo; all the others will leave it as it was (i.e. this will be the global object).

Amadan
  • 169,219
  • 18
  • 195
  • 256
  • sir, can you provide some examples, It will be easy to digest. – Maninder Feb 04 '20 at 12:35
  • 1
    I like to think of it this way - the `this` context is set to whatever you had *before the property accessor* (just the dot `.`) and that happens *when you execute something*. So, `foo.bar.baz.fn()` will execute `fn` with `this = foo.bar.baz`. If you do `foo.fn()` then it's `this = foo`. And if you have `fn()` there is nothing before the dot, so `this = undefined`...and then you get special rules. But it works as a general rule of thumb. If you do `g = foo.bar.fn; g()` you are now executing `g` and there is no property accessor, so `this = undefined`. – VLAZ Feb 04 '20 at 12:36