[JavaScript] Scope (Context) of Event Handler Function


The scope (context) of event handler is headache for new JavaScript developers (at least for me when I try to write JavaScript web application in the beginning). Look at the following code snippet:

1
2
3
4
5
6
7
8
9
contact = function() {
  this.name = 'Bob';

  window.addEventListener("click", this.AddName, false);
};

contact.prototype.AddName = function() {
  alert(this.name);
};

The problems in references [3] and [5] are basically the same as the above. When JavaScript interpreter runs the line 8 of above code, error will be raised. The JavaScript interpreter will tell you that this.name does not exist. You may wonder that this.name is already assigned in line 2, why does the JavaScript interpreter raise error?

The problem is that this keyword in line 8 refers to JavaScript built-in object window, not refers to the contact function object. In line 2, you assign the value 'Bob' to the variable name in the scope (context) of contact function object. As a result, the JavaScript interpreter raises the error.

So how to make the this keyword in line 8 refer to contact function object?

For recent browsers which support Function.prototype.bind natively, you can replace line 4:

window.addEventListener("click", this.AddName, false);

with the following line:

window.addEventListener("click", this.AddName.bind(this), false);

If you want to support old browsers like IE8, you can implement custom Function.prototype.bind, or you can use closures to change the scope (context): line 4 can be replaced with the following code:

var self = this;
window.addEventListener("click", function() {self.AddName();}, false);

Anonymous function and closures are used to make the this keyword in AddName function refer to contact function object.

Other variant of the above problem is described in references [4]. In summary, there are two ways to solve the above problem:

  1. Function.prototype.bind: Only provided in recent browsers, for old browsers, implement custom Function.prototype.bind. See reference [1] for more details.
  2. Closures: See references [2] and [6] for more details.

The questions on Stack Overflow in references [3], [4], [5] are very helpful. Please read carefully.


References:

[1]Function.prototype.bind() - JavaScript | MDN
[2]Objects, event handlers and "this" in javascript – Helephant.com
[3](1, 2) JavaScript Event Handler Scope - Stack Overflow
[4](1, 2) oop - Global Javascript Event Handling Object Context - Stack Overflow
[5](1, 2) javascript - Event Handler Called With Wrong Context - Stack Overflow
[6]Taming the Javascript event scope: Closures