Dario Scattolini
Dario Scattolini

Reputation: 105

Can't understand the behaviour of functions with "this" keyword

I'm trying to figure out the behaviour of "this" keyword in JavaScript. In general I understand how it behaves in different contexts of function calling, but I'm having some trouble when it's part of an arrow function.

I'm using MDN as a source of information: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this#Arrow_functions. I have grasped the general concept that in the case of arrow functions "this" retains the value corresponding to the context of the function definition, but I started having trouble when playing with the last example in that section.

The example goes like this:

var obj = {
  bar: function() {
    var x = (() => this);
    return x;
  }
};

var fn = obj.bar();

console.log(fn() === obj); //true

As expected, the console returns true. However, and this is my first doubt, i don't understand why it returns false when I compare obj directly with obj.bar(), since I asume that obj.bar() and fn() invoke the same function:

var obj = {
  bar: function() {
    var x = (() => this);
    return x;
  }
};

console.log(obj.bar() === obj); //false

I started playing with the code trying to find further unexpected behaviours, and there are some more doubts. The second one: when I change the type of definition of bar, "this" in the function apparently starts referring to the global object, although I thought the function was being called as a method of obj. ¿Shouldn't the result be the opposite? ¿Is it because now "this" refers to the context of fn?

var obj = {
  bar: function() {
    var x = function() {
      return this;
    };
    return x;
  }
};

var fn = obj.bar();

console.log(fn() === obj); //false
console.log(fn() === this); //true

Third doubt: if I omit fn again and use directly obj.bar() in the comparison, again I find unexpected results. In this case "this" in the function refers neither to the global object nor to obj (I expected the second, since bar() is called as a method of obj).

var obj = {
  bar: function() {
    var x = function() {
      return this;
    };
    return x;
  }
};

console.log(obj.bar() === obj); //false
console.log(obj.bar() === this); //false

When I try to see directly the value returned by obj.bar() I can't get much help from the console:

console.log(obj.bar());
//With arrow definition: () => { length:0
//                               name:x }
//With the second definition: f() => { length:0
//                                     name:"bar"
//                                     prototype: bar}

I hope someone here can help me understand what's going on, or at least recommend me a more complete resource. Thank you in advance!

Upvotes: 2

Views: 58

Answers (2)

Bergi
Bergi

Reputation: 665344

I asume that obj.bar() and fn() invoke the same function

No, obj.bar() returns the function x. It's creating a closure.

"this" in the function apparently starts referring to the global object, although I thought the function was being called as a method of obj

No, fn was not called as a method on obj, only bar was. fn() is called as a plain function.

if I omit fn again and use directly obj.bar() in the comparison, "this" in the function refers neither to the global object nor to obj

No. The this in the function is never even evaluated, the function is never called. You only called bar, and then compared the returned function against obj.

When I try to see directly the value returned by obj.bar()

…then the console shows you a function object!

Upvotes: 2

Joy Biswas
Joy Biswas

Reputation: 6527

What you are looking at is obj.bar() reutrns a function that is assigned to a variable fn and then fn is invoked fn()

so

var obj = {
  bar: function() {
    var x = (() => this);
    return x;
  }
};

console.log(obj.bar()() === obj); //should give you true

Upvotes: 1

Related Questions