Preserving a reference to this in JavaScript prototype functions
For preserving the context, the bind
method is really useful, it's now part of the recently released ECMAScript 5th Edition Specification, the implementation of this function is simple (only 8 lines long):
// The .bind method from Prototype.js
if (!Function.prototype.bind) { // check if native implementation available
Function.prototype.bind = function(){
var fn = this, args = Array.prototype.slice.call(arguments),
object = args.shift();
return function(){
return fn.apply(object,
args.concat(Array.prototype.slice.call(arguments)));
};
};
}
And you could use it, in your example like this:
MyClass.prototype.myfunc = function() {
this.element.click((function() {
// ...
}).bind(this));
};
Another example:
var obj = {
test: 'obj test',
fx: function() {
alert(this.test + '\n' + Array.prototype.slice.call(arguments).join());
}
};
var test = "Global test";
var fx1 = obj.fx;
var fx2 = obj.fx.bind(obj, 1, 2, 3);
fx1(1,2);
fx2(4, 5);
In this second example we can observe more about the behavior of bind
.
It basically generates a new function, that will be the responsible of calling our function, preserving the function context (this
value), that is defined as the first argument of bind
.
The rest of the arguments are simply passed to our function.
Note in this example that the function fx1
, is invoked without any object context (obj.method()
), just as a simple function call, in this type of invokation, the this
keyword inside will refer to the Global object, it will alert "global test".
Now, the fx2
is the new function that the bind
method generated, it will call our function preserving the context and correctly passing the arguments, it will alert "obj test 1, 2, 3, 4, 5" because we invoked it adding the two additionally arguments, it already had binded the first three.
Preserve 'this' reference in javascript prototype event handler
I find bind()
being the cleanest solution so far:
this.bar.onclick = this.ClickEvent.bind(this);
BTW the other this
is called that
by convention very often.
How to preserve javascript this context inside singleton pattern?
You can slightly change the way you are returning the object from the anonymous function:
var a = (function () {
var result = {};
result.b = 2;
result.c = function() {
console.log(result.b);
};
return result;
})();
This should have the same effect, however it does remove the use of this
.
If you can't afford to change the structure of a
this much, then alternately you can (much) more dangerously use:
a.c.apply = function() { // Stops the apply function working on a.c by overriding it
return a.c();
}
If you choose this though you must be wary that anytime a.c.apply
is used it will no longer work 'as expected' - it will fix the issue presented here though.
Keeping nested prototype methods from object transfering from WebWorker
I don't want to take any credit from this previous answer, but while the explanation/process through is nice and sound, I believe the proposed solution is not the best one, and btw, I am the author of the flatted library that actually explained, and helped out, in this issue filed against such library, without even knowing there was a discussion here ... sorry I am late ...
The missing piece of the previous answer is that the same instance gets updated over and over while reviving the whole structure, but nothing like that is actually needed, because either Set
or WeakSet
can help speeding up the process, avoiding upgrading what's been upgraded already, over and over.
const {setPrototypeOf} = Reflect;
const upgraded = new Set;
const ret = parse(str, (_, v) => {
if (v && v.className && models[v.className] && !upgraded.has(v)) {
upgraded.add(v);
setPrototypeOf(v, models[v.className].prototype);
}
return v;
});
This change doesn't strictly improve the reason it either works or it is the best solution, compared to substitution, but it takes into account performance and redundant upgrades, 'cause unnecessary setPrototypeOf
calls, might not be desired at all /p>
JavaScript prototype bind
1- The point of adding members on a constructor's prototype, is behavior reuse.
All object instances that inherit from that prototype, will be able to resolve the member through the prototype chain, also the members are defined only once, not in every instance.
2- This happens because each function has its own execution context (that's where the this
value is stored), and the this
value is implicitly set when you invoke a function, and if a function reference has no base object (e.g. foo();
, vs obj.foo()
), the global object will set as the this
value inside the invoked method.
See the second part of this answer for more details.
Edit: After looking your code, seems that you are passing a reference of the nextCallback
method as the callback function of some Ajax success event, if it's so, the base object of the reference will be lost, a common approach that can be to use an anonymous function that invokes correctly your method, for example:
var obj = new Test();
//...
someAjaxLib(url, function (data) {
obj.nextCallback(data); // `this` will refer to obj within nextCallback
});
Another approach can be to bind a method to its instance within the constructor, keep in mind that the method will be defined as an own property on each object instance you create, it will not be inherited, for example:
function Test() {
var instance = this; // store reference to the current instance
this.nextCallback = function( response ) {
if( response.Status != 'SUCCESS' ) {
show_message( response.Message, false );
} else {
instance.setQuestion( response.Question ); // use the stored reference
}
}
}
How to access the correct `this` inside a callback
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:
function foo() {
console.log(this);
}
// normal function call
foo(); // `this` will refer to `window`
// as object method
var obj = {bar: foo};
obj.bar(); // `this` will refer to `obj`
// as constructor function
new foo(); // `this` will refer to an object that inherits from `foo.prototype`
To learn more about this
, have a look at the MDN documentation.
How to refer to the correct this
Use arrow functions
ECMAScript 6 introduced 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 behavior they have, please refer to the MDN documentation for more information.
function MyConstructor(data, transport) {
this.data = data;
transport.on('data', () => alert(this.data));
}
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 are self
and that
.
function MyConstructor(data, transport) {
this.data = data;
var self = this;
transport.on('data', function() {
alert(self.data);
});
}
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 the this
value of the callback itself.
Explicitly set this
of the callback - part 1
It 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 with this
bound to a value. The function has exactly the same behavior as the one you called .bind
on, only that this
was set by you. No matter how or when that function is called, this
will always refer to the passed value.
function MyConstructor(data, transport) {
this.data = data;
var boundFunction = (function() { // parenthesis are not necessary
alert(this.data); // but might improve readability
}).bind(this); // <- here we are calling `.bind()`
transport.on('data', boundFunction);
}
In this case, we are binding the callback's this
to the value of MyConstructor
's this
.
Note: When a 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.
Set this
of the callback - part 2
Some 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:
array.map(callback[, thisArg])
The first argument is the callback and the second argument is the value this
should refer to. Here is a contrived example:
var arr = [1, 2, 3];
var obj = {multiplier: 42};
var new_arr = arr.map(function(v) {
return v * this.multiplier;
}, obj); // <- here we are passing `obj` as second argument
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 called context
:
This object will be made the context of all Ajax-related callbacks.
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:
function Foo() {
this.data = 42,
document.body.onclick = this.method;
}
Foo.prototype.method = function() {
console.log(this.data);
};
The function this.method
is assigned as click event handler, but if the document.body
is clicked, the value logged will be undefined
, because inside the event handler, this
refers to the document.body
, not the instance of Foo
.
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:
function method() {
console.log(this.data);
}
function Foo() {
this.data = 42,
document.body.onclick = this.method;
}
Foo.prototype.method = method;
The solution is the same as mentioned above: If available, use .bind
to explicitly bind this
to a specific value
document.body.onclick = this.method.bind(this);
or 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:
var self = this;
document.body.onclick = function() {
self.method();
};
or use an arrow function:
document.body.onclick = () => this.method();
Related Topics
Jquery.Parsejson Throws "Invalid JSON" Error Due to Escaped Single Quote in JSON
Why Is [1,2] + [3,4] = "1,23,4" in JavaScript
How to Check for an Undefined or Null Variable in JavaScript
How to Get Node Datum on Mouseover in D3 V6
How to Find Out What Character Key Is Pressed
Using JavaScript's Atob to Decode Base64 Doesn't Properly Decode Utf-8 Strings
Differencebetween Children and Childnodes in JavaScript
Javascript: Filter() for Objects
The Value of "This" Within the Handler Using Addeventlistener
Emberjs: How to Load Multiple Models on the Same Route
How to Turn a String into a JavaScript Function Call
JavaScript Regex: How to Put a Variable Inside a Regular Expression
Javascript: Inline Script with Src Attribute
Difference Between 'Return Await Promise' and 'Return Promise'
Can You Get a Users Local Lan Ip Address via JavaScript
Replace Multiple Characters in One Replace Call
Assigning Prototype Methods *Inside* the Constructor Function - Why Not
Is There a More Accurate Way to Create a JavaScript Timer Than Settimeout