3

I have confused myself in the following case:

function foo() {
}

foo.prototype.bar1 = function() {
  console.log(this); // shows "Window"!!
}

foo.prototype.bar2 = function(func) {
  func();
}

var f = new foo();
f.bar2(f.bar1);

How/Why could the result of console.log(this) is "Window"? I thought no matter how you call public function of a class here, "this" should always refer to "foo".

And also what is right way to avoid this kind of error?

Thanks

Linghua Jin
  • 570
  • 2
  • 6
  • 22
  • The rules are no different than any other function invocation (see http://stackoverflow.com/questions/16382165/why-do-i-lose-the-context-of-this-in-javascript). `Function.prototype.bind` (or an emulation) can be useful here, as can general closures. – user2246674 May 06 '13 at 02:44
  • You can use `func.apply(this)` to get expected behavior, I think. – Waleed Khan May 06 '13 at 02:48
  • `func.call(this)` should do. – elclanrs May 06 '13 at 02:50
  • @WaleedKhan But that's a special case that works *specifically* here because the ThisBinding when `bar2` is executed is "expected". – user2246674 May 06 '13 at 02:50
  • this keyword is quite a complex issue in js. It invovles: window object, prototype, call/apply method and probably more. I recommend this book: javscript enlightment. Very helpful, I think http://www.javascriptenlightenment.com/JavaScript_Enlightenment.pdf – Herrington Darkholme May 06 '13 at 03:07
  • See my previous answer to this related question: http://stackoverflow.com/questions/13441307/how-does-the-this-keyword-in-javascript-act-within-an-object-literal/13441628#13441628 – slebetman May 06 '13 at 03:25

1 Answers1

1

When you do f.bar2(f.bar1), you're passing a reference of bar1 to bar2; inside bar2, it's only known as "func", and the connection with f is lost. The value of this is determined dynamically when the function is invoked. If you invoke f.bar1(), this will be f, but when you invoke func(), it's undefined, and will fall back to the global object (window).

I have explained this earlier as follows:

The basic rules are, this will be the global object unless:

  • the function is called as an object method (then this will be the object), or
  • the function is called as a constructor, with the new operator (in which case this will point to the new object being constructed)

One way to avoid that is to create a bound function and pass that:

f.bar2(f.bar1.bind(f));

Note that Function.prototype.bind is not supported by older browsers, so you might need a polyfill (there's one available on MDN).

In the simple scenario you presented, you can do what elclanrs suggests in his comment, as the target this is available inside bar2:

func.call(this);
Community
  • 1
  • 1
bfavaretto
  • 71,580
  • 16
  • 111
  • 150