I have a constructor function which registers an event handler:
function MyConstructor(data, transport) {
this.data = data;
transport.on('data', function () {
alert(this.data);
});
}
// Mock transport object
var transport = {
on: function(event, callback) {
setTimeout(callback, 1000);
}
};
// called as
var obj = new MyConstructor('foo', transport);
However, I'm not able to access the data
property of the created object inside the callback. It looks like this
does not refer to the object that was created but to an other one.
I also tried to use an object method instead of an anonymous function:
function MyConstructor(data, transport) {
this.data = data;
transport.on('data', this.alert);
}
MyConstructor.prototype.alert = function() {
alert(this.name);
};
but it exhibits the same problems.
How can I access the correct object?
It's all in the "magic" syntax of calling a method:
When you get the property from the object and call it in one go, the object will be the context for the method. If you call the same method, but in separate steps, the context is the global scope (window) instead:
When you get the reference of a method, it's no longer attached to the object, it's just a reference to a plain function. The same happens when you get the reference to use as a callback:
That's where you would bind the context to the function:
If you are using jQuery you should use the
$.proxy
method instead, asbind
is not supported in all browsers:Another approach, which is the standard way since DOM2 to bind
this
within the event listener, that let you always remove the listener (among other benefits), is thehandleEvent(evt)
method from theEventListener
interface:Detailed information about using
handleEvent
can be found here: https://medium.com/@WebReflection/dom-handleevent-a-cross-platform-standard-since-year-2000-5bf17287fd38You Should know about "this" Keyword.
As per my view you can implement "this" in three ways (Self/Arrow function/Bind Method)
A function's this keyword behaves a little differently in JavaScript compared to other languages.
It also has some differences between strict mode and non-strict mode.
In most cases, the value of this is determined by how a function is called.
It can't be set by assignment during execution, and it may be different each time the function is called.
ES5 introduced the bind() method to set the value of a function's this regardless of how it's called,
and ES2015 introduced arrow functions which don't provide their own this binding (it retains the this value of the enclosing lexical context).
Method1: Self - Self is being used to maintain a reference to the original this even as the context is changing. It's a technique often used in event handlers (especially in closures).
Reference : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this
Method2: Arrow function - An arrow function expression is a syntactically compact alternative to a regular function expression,
although without its own bindings to the this, arguments, super, or new.target keywords.
Arrow function expressions are ill suited as methods, and they cannot be used as constructors.
Reference: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions
Method3:Bind- The bind() method creates a new function that,
when called, has its this keyword set to the provided value,
with a given sequence of arguments preceding any provided when the new function is called.
Reference: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_objects/Function/bind
Here are several ways to access parent context inside child context -
bind()
function.1. Use
bind()
functionIf you are using
underscore.js
- http://underscorejs.org/#bind2 Store reference to context/this inside another variable
3 Arrow function
What you should know about
this
this
(aka "the context") is a special keyword inside each function and its value only depends on how the function was called, not how/when/where it was defined. It is not affected by lexical scopes like other variables (except for arrow functions, see below). Here are some examples:To learn more about
this
, have a look at the MDN documentation.How to refer to the correct
this
Don't use
this
You actually don't want to access
this
in particular, but the object it refers to. That's why an easy solution is to simply create a new variable that also refers to that object. The variable can have any name, but common ones areself
andthat
.Since
self
is a normal variable, it obeys lexical scope rules and is accessible inside the callback. This also has the advantage that you can access thethis
value of the callback itself.Explicitly set
this
of the callback - part 1It might look like you have no control over the value of
this
because its value is set automatically, but that is actually not the case.Every function has the method
.bind
[docs], which returns a new function withthis
bound to a value. The function has exactly the same behaviour as the one you called.bind
on, only thatthis
was set by you. No matter how or when that function is called,this
will always refer to the passed value.In this case, we are binding the callback's
this
to the value ofMyConstructor
'sthis
.Note: When binding context for jQuery, use
jQuery.proxy
[docs] instead. The reason to do this is so that you don't need to store the reference to the function when unbinding an event callback. jQuery handles that internally.ECMAScript 6: Use arrow functions
ECMAScript 6 introduces arrow functions, which can be thought of as lambda functions. They don't have their own
this
binding. Instead,this
is looked up in scope just like a normal variable. That means you don't have to call.bind
. That's not the only special behaviour they have, please refer to the MDN documentation for more information.Set
this
of the callback - part 2Some functions/methods which accept callbacks also accept a value to which the callback's
this
should refer to. This is basically the same as binding it yourself, but the function/method does it for you.Array#map
[docs] is such a method. Its signature is:The first argument is the callback and the second argument is the value
this
should refer to. Here is a contrived example:Note: Whether or not you can pass a value for
this
is usually mentioned in the documentation of that function/method. For example, jQuery's$.ajax
method [docs] describes an option calledcontext
:Common problem: Using object methods as callbacks/event handlers
Another common manifestation of this problem is when an object method is used as callback/event handler. Functions are first-class citizens in JavaScript and the term "method" is just a colloquial term for a function that is a value of an object property. But that function doesn't have a specific link to its "containing" object.
Consider the following example:
The function
this.method
is assigned as click event handler, but if thedocument.body
is clicked, the value logged will beundefined
, because inside the event handler,this
refers to thedocument.body
, not the instance ofFoo
.As already mentioned at the beginning, what
this
refers to depends on how the function is called, not how it is defined.If the code was like the following, it might be more obvious that the function doesn't have an implicit reference to the object:
The solution is the same as mentioned above: If available, use
.bind
to explicitly bindthis
to a specific valueor explicitly call the function as a "method" of the object, by using an anonymous function as callback / event handler and assign the object (
this
) to another variable:or use an arrow function:
We can not bind this to
setTimeout()
, as it always execute with global object (Window), if you want to accessthis
context in the callback function then by usingbind()
to the callback function we can achieve as: