Related
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 another 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?
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();
Here are several ways to access the parent context inside a child context -
You can use the bind() function.
Store a reference to context/this inside another variable (see the below example).
Use ES6 Arrow functions.
Alter the code, function design, and architecture - for this you should have command over design patterns in JavaScript.
1. Use the bind() function
function MyConstructor(data, transport) {
this.data = data;
transport.on('data', ( function () {
alert(this.data);
}).bind(this) );
}
// Mock transport object
var transport = {
on: function(event, callback) {
setTimeout(callback, 1000);
}
};
// called as
var obj = new MyConstructor('foo', transport);
If you are using Underscore.js - http://underscorejs.org/#bind
transport.on('data', _.bind(function () {
alert(this.data);
}, this));
2. Store a reference to context/this inside another variable
function MyConstructor(data, transport) {
var self = this;
this.data = data;
transport.on('data', function() {
alert(self.data);
});
}
3. Arrow function
function MyConstructor(data, transport) {
this.data = data;
transport.on('data', () => {
alert(this.data);
});
}
It's all in the "magic" syntax of calling a method:
object.property();
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:
var f = object.property;
f();
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:
this.saveNextLevelData(this.setAll);
That's where you would bind the context to the function:
this.saveNextLevelData(this.setAll.bind(this));
If you are using jQuery you should use the $.proxy method instead, as bind is not supported in all browsers:
this.saveNextLevelData($.proxy(this.setAll, this));
You 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 that don't provide their own this binding (it retains 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: this
function MyConstructor(data, transport) {
this.data = data;
var self = this;
transport.on('data', function () {
alert(self.data);
});
}
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: Arrow function expressions
function MyConstructor(data, transport) {
this.data = data;
transport.on('data',()=> {
alert(this.data);
});
}
Method 3: 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: Function.prototype.bind()
function MyConstructor(data, transport) {
this.data = data;
transport.on('data',(function() {
alert(this.data);
}).bind(this);
The trouble with "context"
The term "context" is sometimes used to refer to the object referenced by this. Its use is inappropriate, because it doesn't fit either semantically or technically with ECMAScript's this.
"Context" means the circumstances surrounding something that adds meaning, or some preceding and following information that gives extra meaning. The term "context" is used in ECMAScript to refer to execution context, which is all the parameters, scope, and this within the scope of some executing code.
This is shown in ECMA-262 section 10.4.2:
Set the ThisBinding to the same value as the ThisBinding of the
calling execution context
Which clearly indicates that this is part of an execution context.
An execution context provides the surrounding information that adds meaning to the code that is being executed. It includes much more information than just the thisBinding.
The value of this isn't "context". It's just one part of an execution context. It's essentially a local variable that can be set by the call to any object and in strict mode, to any value at all.
First, you need to have a clear understanding of scope and behaviour of the this keyword in the context of scope.
this & scope:
There are two types of scope in JavaScript. They are:
Global Scope
Function Scope
In short, global scope refers to the window object. Variables declared in a global scope are accessible from anywhere.
On the other hand, function scope resides inside of a function. A variable declared inside a function cannot be accessed from the outside world normally.
The this keyword in the global scope refers to the window object. this inside a function also refers to the window object. So this will always refer to the window until we find a way to manipulate this to indicate a context of our own choosing.
--------------------------------------------------------------------------------
- -
- Global Scope -
- (globally "this" refers to window object) -
- -
- function outer_function(callback){ -
- -
- // Outer function scope -
- // Inside the outer function, the "this" keyword -
- // refers to window object -
- callback() // "this" inside callback also refers to the window object -
- } -
- -
- function callback_function(){ -
- -
- // Function to be passed as callback -
- -
- // Here "THIS" refers to the window object also -
- } -
- -
- outer_function(callback_function) -
- // Invoke with callback -
- -
--------------------------------------------------------------------------------
Different ways to manipulate this inside callback functions:
Here I have a constructor function called Person. It has a property called name and four method called sayNameVersion1, sayNameVersion2, sayNameVersion3, and sayNameVersion4. All four of them has one specific task. Accept a callback and invoke it. The callback has a specific task which is to log the name property of an instance of Person constructor function.
function Person(name){
this.name = name
this.sayNameVersion1 = function(callback){
callback.bind(this)()
}
this.sayNameVersion2 = function(callback){
callback()
}
this.sayNameVersion3 = function(callback){
callback.call(this)
}
this.sayNameVersion4 = function(callback){
callback.apply(this)
}
}
function niceCallback(){
// Function to be used as callback
var parentObject = this
console.log(parentObject)
}
Now let's create an instance from person constructor and invoke different versions of sayNameVersionX (X refers to 1,2,3,4) method with niceCallback to see how many ways we can manipulate the this inside callback to refer to the person instance.
var p1 = new Person('zami') // Create an instance of Person constructor
bind:
What bind do is to create a new function with the this keyword set to the provided value.
sayNameVersion1 and sayNameVersion2 use bind to manipulate this of the callback function.
this.sayNameVersion1 = function(callback){
callback.bind(this)()
}
this.sayNameVersion2 = function(callback){
callback()
}
The first one binds this with a callback inside the method itself. And for the second one, the callback is passed with the object bound to it.
p1.sayNameVersion1(niceCallback) // pass simply the callback and bind happens inside the sayNameVersion1 method
p1.sayNameVersion2(niceCallback.bind(p1)) // uses bind before passing callback
call:
The first argument of the call method is used as this inside the function that is invoked with call attached to it.
sayNameVersion3 uses call to manipulate the this to refer to the person object that we created, instead of the window object.
this.sayNameVersion3 = function(callback){
callback.call(this)
}
And it is called like the following:
p1.sayNameVersion3(niceCallback)
apply:
Similar to call, the first argument of apply refers to the object that will be indicated by the this keyword.
sayNameVersion4 uses apply to manipulate this to refer to a person object
this.sayNameVersion4 = function(callback){
callback.apply(this)
}
And it is called like the following. Simply the callback is passed,
p1.sayNameVersion4(niceCallback)
We can not bind this to setTimeout(), as it always executes with the global object (Window). If you want to access the this context in the callback function then by using bind() to the callback function, we can achieve it as:
setTimeout(function(){
this.methodName();
}.bind(this), 2000);
The question revolves around how the this keyword behaves in JavaScript. this behaves differently as below,
The value of this is usually determined by a function execution context.
In the global scope, this refers to the global object (the window object).
If strict mode is enabled for any function then the value of this will be undefined as in strict mode, global object refers to undefined in place of the window object.
The object that is standing before the dot is what the this keyword will be bound to.
We can set the value of this explicitly with call(), bind(), and apply()
When the new keyword is used (a constructor), this is bound to the new object being created.
Arrow functions don’t bind this — instead, this is bound lexically (i.e., based on the original context)
As most of the answers suggest, we can use the arrow function or bind() Method or Self var. I would quote a point about lambdas (arrow function) from Google JavaScript Style Guide
Prefer using arrow functions over f.bind(this), and especially over
goog.bind(f, this). Avoid writing const self = this. Arrow functions
are particularly useful for callbacks, which sometimes pass unexpectedly
additional arguments.
Google clearly recommends using lambdas rather than bind or const self = this
So the best solution would be to use lambdas as below,
function MyConstructor(data, transport) {
this.data = data;
transport.on('data', () => {
alert(this.data);
});
}
References:
https://medium.com/tech-tajawal/javascript-this-4-rules-7354abdb274c
arrow-functions-vs-bind
Currently there is another approach possible if classes are used in code.
With support of class fields, it's possible to make it the following way:
class someView {
onSomeInputKeyUp = (event) => {
console.log(this); // This refers to the correct value
// ....
someInitMethod() {
//...
someInput.addEventListener('input', this.onSomeInputKeyUp)
For sure under the hood it's all the old good arrow function that binds context, but in this form it looks much more clear that explicit binding.
Since it's a Stage 3 Proposal, you will need Babel and appropriate Babel plugin to process it as for now (08/2018).
I was facing a problem with Ngx line chart xAxisTickFormatting function which was called from HTML like this: [xAxisTickFormatting]="xFormat".
I was unable to access my component's variable from the function declared. This solution helped me to resolve the issue to find the correct this.
Instead of using the function like this:
xFormat (value): string {
return value.toString() + this.oneComponentVariable; //gives wrong result
}
Use this:
xFormat = (value) => {
// console.log(this);
// now you have access to your component variables
return value + this.oneComponentVariable
}
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 the handleEvent(evt) method from the EventListener interface:
var obj = {
handleEvent(e) {
// always true
console.log(this === obj);
}
};
document.body.addEventListener('click', obj);
Detailed information about using handleEvent can be found here: DOM handleEvent: a cross-platform standard since year 2000
Some other people have touched on how to use the .bind() method, but specifically here is how you can use it with .then() if anyone is having trouble getting them to work together:
someFunction()
.then(function(response) {
//'this' wasn't accessible here before but now it is
}.bind(this))
As mentioned in the comments, an alternative would be to use an arrow function that doesn't have its own 'this' value
someFunction()
.then((response)=>{
//'this' was always accessible here
})
this in JavaScript:
The value of this in JavaScript is 100% determined by how a function is called, and not how it is defined. We can relatively easily find the value of this by the 'left of the dot rule':
When the function is created using the function keyword the value of this is the object left of the dot of the function which is called
If there is no object left of the dot then the value of this inside a function is often the global object (global in Node.js and window in a browser). I wouldn't recommend using the this keyword here because it is less explicit than using something like window!
There exist certain constructs like arrow functions and functions created using the Function.prototype.bind() a function that can fix the value of this. These are exceptions of the rule, but they are really helpful to fix the value of this.
Example in Node.js
module.exports.data = 'module data';
// This outside a function in node refers to module.exports object
console.log(this);
const obj1 = {
data: "obj1 data",
met1: function () {
console.log(this.data);
},
met2: () => {
console.log(this.data);
},
};
const obj2 = {
data: "obj2 data",
test1: function () {
console.log(this.data);
},
test2: function () {
console.log(this.data);
}.bind(obj1),
test3: obj1.met1,
test4: obj1.met2,
};
obj2.test1();
obj2.test2();
obj2.test3();
obj2.test4();
obj1.met1.call(obj2);
Output:
Let me walk you through the outputs one by one (ignoring the first log starting from the second):
this is obj2 because of the left of the dot rule, we can see how test1 is called obj2.test1();. obj2 is left of the dot and thus the this value.
Even though obj2 is left of the dot, test2 is bound to obj1 via the bind() method. The this value is obj1.
obj2 is left of the dot from the function which is called: obj2.test3(). Therefore obj2 will be the value of this.
In this case: obj2.test4() obj2 is left of the dot. However, arrow functions don't have their own this binding. Therefore it will bind to the this value of the outer scope which is the module.exports an object which was logged in the beginning.
We can also specify the value of this by using the call function. Here we can pass in the desired this value as an argument, which is obj2 in this case.
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 another 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?
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();
Here are several ways to access the parent context inside a child context -
You can use the bind() function.
Store a reference to context/this inside another variable (see the below example).
Use ES6 Arrow functions.
Alter the code, function design, and architecture - for this you should have command over design patterns in JavaScript.
1. Use the bind() function
function MyConstructor(data, transport) {
this.data = data;
transport.on('data', ( function () {
alert(this.data);
}).bind(this) );
}
// Mock transport object
var transport = {
on: function(event, callback) {
setTimeout(callback, 1000);
}
};
// called as
var obj = new MyConstructor('foo', transport);
If you are using Underscore.js - http://underscorejs.org/#bind
transport.on('data', _.bind(function () {
alert(this.data);
}, this));
2. Store a reference to context/this inside another variable
function MyConstructor(data, transport) {
var self = this;
this.data = data;
transport.on('data', function() {
alert(self.data);
});
}
3. Arrow function
function MyConstructor(data, transport) {
this.data = data;
transport.on('data', () => {
alert(this.data);
});
}
It's all in the "magic" syntax of calling a method:
object.property();
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:
var f = object.property;
f();
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:
this.saveNextLevelData(this.setAll);
That's where you would bind the context to the function:
this.saveNextLevelData(this.setAll.bind(this));
If you are using jQuery you should use the $.proxy method instead, as bind is not supported in all browsers:
this.saveNextLevelData($.proxy(this.setAll, this));
You 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 that don't provide their own this binding (it retains 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: this
function MyConstructor(data, transport) {
this.data = data;
var self = this;
transport.on('data', function () {
alert(self.data);
});
}
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: Arrow function expressions
function MyConstructor(data, transport) {
this.data = data;
transport.on('data',()=> {
alert(this.data);
});
}
Method 3: 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: Function.prototype.bind()
function MyConstructor(data, transport) {
this.data = data;
transport.on('data',(function() {
alert(this.data);
}).bind(this);
The trouble with "context"
The term "context" is sometimes used to refer to the object referenced by this. Its use is inappropriate, because it doesn't fit either semantically or technically with ECMAScript's this.
"Context" means the circumstances surrounding something that adds meaning, or some preceding and following information that gives extra meaning. The term "context" is used in ECMAScript to refer to execution context, which is all the parameters, scope, and this within the scope of some executing code.
This is shown in ECMA-262 section 10.4.2:
Set the ThisBinding to the same value as the ThisBinding of the
calling execution context
Which clearly indicates that this is part of an execution context.
An execution context provides the surrounding information that adds meaning to the code that is being executed. It includes much more information than just the thisBinding.
The value of this isn't "context". It's just one part of an execution context. It's essentially a local variable that can be set by the call to any object and in strict mode, to any value at all.
First, you need to have a clear understanding of scope and behaviour of the this keyword in the context of scope.
this & scope:
There are two types of scope in JavaScript. They are:
Global Scope
Function Scope
In short, global scope refers to the window object. Variables declared in a global scope are accessible from anywhere.
On the other hand, function scope resides inside of a function. A variable declared inside a function cannot be accessed from the outside world normally.
The this keyword in the global scope refers to the window object. this inside a function also refers to the window object. So this will always refer to the window until we find a way to manipulate this to indicate a context of our own choosing.
--------------------------------------------------------------------------------
- -
- Global Scope -
- (globally "this" refers to window object) -
- -
- function outer_function(callback){ -
- -
- // Outer function scope -
- // Inside the outer function, the "this" keyword -
- // refers to window object -
- callback() // "this" inside callback also refers to the window object -
- } -
- -
- function callback_function(){ -
- -
- // Function to be passed as callback -
- -
- // Here "THIS" refers to the window object also -
- } -
- -
- outer_function(callback_function) -
- // Invoke with callback -
- -
--------------------------------------------------------------------------------
Different ways to manipulate this inside callback functions:
Here I have a constructor function called Person. It has a property called name and four method called sayNameVersion1, sayNameVersion2, sayNameVersion3, and sayNameVersion4. All four of them has one specific task. Accept a callback and invoke it. The callback has a specific task which is to log the name property of an instance of Person constructor function.
function Person(name){
this.name = name
this.sayNameVersion1 = function(callback){
callback.bind(this)()
}
this.sayNameVersion2 = function(callback){
callback()
}
this.sayNameVersion3 = function(callback){
callback.call(this)
}
this.sayNameVersion4 = function(callback){
callback.apply(this)
}
}
function niceCallback(){
// Function to be used as callback
var parentObject = this
console.log(parentObject)
}
Now let's create an instance from person constructor and invoke different versions of sayNameVersionX (X refers to 1,2,3,4) method with niceCallback to see how many ways we can manipulate the this inside callback to refer to the person instance.
var p1 = new Person('zami') // Create an instance of Person constructor
bind:
What bind do is to create a new function with the this keyword set to the provided value.
sayNameVersion1 and sayNameVersion2 use bind to manipulate this of the callback function.
this.sayNameVersion1 = function(callback){
callback.bind(this)()
}
this.sayNameVersion2 = function(callback){
callback()
}
The first one binds this with a callback inside the method itself. And for the second one, the callback is passed with the object bound to it.
p1.sayNameVersion1(niceCallback) // pass simply the callback and bind happens inside the sayNameVersion1 method
p1.sayNameVersion2(niceCallback.bind(p1)) // uses bind before passing callback
call:
The first argument of the call method is used as this inside the function that is invoked with call attached to it.
sayNameVersion3 uses call to manipulate the this to refer to the person object that we created, instead of the window object.
this.sayNameVersion3 = function(callback){
callback.call(this)
}
And it is called like the following:
p1.sayNameVersion3(niceCallback)
apply:
Similar to call, the first argument of apply refers to the object that will be indicated by the this keyword.
sayNameVersion4 uses apply to manipulate this to refer to a person object
this.sayNameVersion4 = function(callback){
callback.apply(this)
}
And it is called like the following. Simply the callback is passed,
p1.sayNameVersion4(niceCallback)
We can not bind this to setTimeout(), as it always executes with the global object (Window). If you want to access the this context in the callback function then by using bind() to the callback function, we can achieve it as:
setTimeout(function(){
this.methodName();
}.bind(this), 2000);
The question revolves around how the this keyword behaves in JavaScript. this behaves differently as below,
The value of this is usually determined by a function execution context.
In the global scope, this refers to the global object (the window object).
If strict mode is enabled for any function then the value of this will be undefined as in strict mode, global object refers to undefined in place of the window object.
The object that is standing before the dot is what the this keyword will be bound to.
We can set the value of this explicitly with call(), bind(), and apply()
When the new keyword is used (a constructor), this is bound to the new object being created.
Arrow functions don’t bind this — instead, this is bound lexically (i.e., based on the original context)
As most of the answers suggest, we can use the arrow function or bind() Method or Self var. I would quote a point about lambdas (arrow function) from Google JavaScript Style Guide
Prefer using arrow functions over f.bind(this), and especially over
goog.bind(f, this). Avoid writing const self = this. Arrow functions
are particularly useful for callbacks, which sometimes pass unexpectedly
additional arguments.
Google clearly recommends using lambdas rather than bind or const self = this
So the best solution would be to use lambdas as below,
function MyConstructor(data, transport) {
this.data = data;
transport.on('data', () => {
alert(this.data);
});
}
References:
https://medium.com/tech-tajawal/javascript-this-4-rules-7354abdb274c
arrow-functions-vs-bind
Currently there is another approach possible if classes are used in code.
With support of class fields, it's possible to make it the following way:
class someView {
onSomeInputKeyUp = (event) => {
console.log(this); // This refers to the correct value
// ....
someInitMethod() {
//...
someInput.addEventListener('input', this.onSomeInputKeyUp)
For sure under the hood it's all the old good arrow function that binds context, but in this form it looks much more clear that explicit binding.
Since it's a Stage 3 Proposal, you will need Babel and appropriate Babel plugin to process it as for now (08/2018).
I was facing a problem with Ngx line chart xAxisTickFormatting function which was called from HTML like this: [xAxisTickFormatting]="xFormat".
I was unable to access my component's variable from the function declared. This solution helped me to resolve the issue to find the correct this.
Instead of using the function like this:
xFormat (value): string {
return value.toString() + this.oneComponentVariable; //gives wrong result
}
Use this:
xFormat = (value) => {
// console.log(this);
// now you have access to your component variables
return value + this.oneComponentVariable
}
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 the handleEvent(evt) method from the EventListener interface:
var obj = {
handleEvent(e) {
// always true
console.log(this === obj);
}
};
document.body.addEventListener('click', obj);
Detailed information about using handleEvent can be found here: DOM handleEvent: a cross-platform standard since year 2000
Some other people have touched on how to use the .bind() method, but specifically here is how you can use it with .then() if anyone is having trouble getting them to work together:
someFunction()
.then(function(response) {
//'this' wasn't accessible here before but now it is
}.bind(this))
As mentioned in the comments, an alternative would be to use an arrow function that doesn't have its own 'this' value
someFunction()
.then((response)=>{
//'this' was always accessible here
})
this in JavaScript:
The value of this in JavaScript is 100% determined by how a function is called, and not how it is defined. We can relatively easily find the value of this by the 'left of the dot rule':
When the function is created using the function keyword the value of this is the object left of the dot of the function which is called
If there is no object left of the dot then the value of this inside a function is often the global object (global in Node.js and window in a browser). I wouldn't recommend using the this keyword here because it is less explicit than using something like window!
There exist certain constructs like arrow functions and functions created using the Function.prototype.bind() a function that can fix the value of this. These are exceptions of the rule, but they are really helpful to fix the value of this.
Example in Node.js
module.exports.data = 'module data';
// This outside a function in node refers to module.exports object
console.log(this);
const obj1 = {
data: "obj1 data",
met1: function () {
console.log(this.data);
},
met2: () => {
console.log(this.data);
},
};
const obj2 = {
data: "obj2 data",
test1: function () {
console.log(this.data);
},
test2: function () {
console.log(this.data);
}.bind(obj1),
test3: obj1.met1,
test4: obj1.met2,
};
obj2.test1();
obj2.test2();
obj2.test3();
obj2.test4();
obj1.met1.call(obj2);
Output:
Let me walk you through the outputs one by one (ignoring the first log starting from the second):
this is obj2 because of the left of the dot rule, we can see how test1 is called obj2.test1();. obj2 is left of the dot and thus the this value.
Even though obj2 is left of the dot, test2 is bound to obj1 via the bind() method. The this value is obj1.
obj2 is left of the dot from the function which is called: obj2.test3(). Therefore obj2 will be the value of this.
In this case: obj2.test4() obj2 is left of the dot. However, arrow functions don't have their own this binding. Therefore it will bind to the this value of the outer scope which is the module.exports an object which was logged in the beginning.
We can also specify the value of this by using the call function. Here we can pass in the desired this value as an argument, which is obj2 in this case.
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 another 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?
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();
Here are several ways to access the parent context inside a child context -
You can use the bind() function.
Store a reference to context/this inside another variable (see the below example).
Use ES6 Arrow functions.
Alter the code, function design, and architecture - for this you should have command over design patterns in JavaScript.
1. Use the bind() function
function MyConstructor(data, transport) {
this.data = data;
transport.on('data', ( function () {
alert(this.data);
}).bind(this) );
}
// Mock transport object
var transport = {
on: function(event, callback) {
setTimeout(callback, 1000);
}
};
// called as
var obj = new MyConstructor('foo', transport);
If you are using Underscore.js - http://underscorejs.org/#bind
transport.on('data', _.bind(function () {
alert(this.data);
}, this));
2. Store a reference to context/this inside another variable
function MyConstructor(data, transport) {
var self = this;
this.data = data;
transport.on('data', function() {
alert(self.data);
});
}
3. Arrow function
function MyConstructor(data, transport) {
this.data = data;
transport.on('data', () => {
alert(this.data);
});
}
It's all in the "magic" syntax of calling a method:
object.property();
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:
var f = object.property;
f();
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:
this.saveNextLevelData(this.setAll);
That's where you would bind the context to the function:
this.saveNextLevelData(this.setAll.bind(this));
If you are using jQuery you should use the $.proxy method instead, as bind is not supported in all browsers:
this.saveNextLevelData($.proxy(this.setAll, this));
You 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 that don't provide their own this binding (it retains 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: this
function MyConstructor(data, transport) {
this.data = data;
var self = this;
transport.on('data', function () {
alert(self.data);
});
}
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: Arrow function expressions
function MyConstructor(data, transport) {
this.data = data;
transport.on('data',()=> {
alert(this.data);
});
}
Method 3: 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: Function.prototype.bind()
function MyConstructor(data, transport) {
this.data = data;
transport.on('data',(function() {
alert(this.data);
}).bind(this);
The trouble with "context"
The term "context" is sometimes used to refer to the object referenced by this. Its use is inappropriate, because it doesn't fit either semantically or technically with ECMAScript's this.
"Context" means the circumstances surrounding something that adds meaning, or some preceding and following information that gives extra meaning. The term "context" is used in ECMAScript to refer to execution context, which is all the parameters, scope, and this within the scope of some executing code.
This is shown in ECMA-262 section 10.4.2:
Set the ThisBinding to the same value as the ThisBinding of the
calling execution context
Which clearly indicates that this is part of an execution context.
An execution context provides the surrounding information that adds meaning to the code that is being executed. It includes much more information than just the thisBinding.
The value of this isn't "context". It's just one part of an execution context. It's essentially a local variable that can be set by the call to any object and in strict mode, to any value at all.
First, you need to have a clear understanding of scope and behaviour of the this keyword in the context of scope.
this & scope:
There are two types of scope in JavaScript. They are:
Global Scope
Function Scope
In short, global scope refers to the window object. Variables declared in a global scope are accessible from anywhere.
On the other hand, function scope resides inside of a function. A variable declared inside a function cannot be accessed from the outside world normally.
The this keyword in the global scope refers to the window object. this inside a function also refers to the window object. So this will always refer to the window until we find a way to manipulate this to indicate a context of our own choosing.
--------------------------------------------------------------------------------
- -
- Global Scope -
- (globally "this" refers to window object) -
- -
- function outer_function(callback){ -
- -
- // Outer function scope -
- // Inside the outer function, the "this" keyword -
- // refers to window object -
- callback() // "this" inside callback also refers to the window object -
- } -
- -
- function callback_function(){ -
- -
- // Function to be passed as callback -
- -
- // Here "THIS" refers to the window object also -
- } -
- -
- outer_function(callback_function) -
- // Invoke with callback -
- -
--------------------------------------------------------------------------------
Different ways to manipulate this inside callback functions:
Here I have a constructor function called Person. It has a property called name and four method called sayNameVersion1, sayNameVersion2, sayNameVersion3, and sayNameVersion4. All four of them has one specific task. Accept a callback and invoke it. The callback has a specific task which is to log the name property of an instance of Person constructor function.
function Person(name){
this.name = name
this.sayNameVersion1 = function(callback){
callback.bind(this)()
}
this.sayNameVersion2 = function(callback){
callback()
}
this.sayNameVersion3 = function(callback){
callback.call(this)
}
this.sayNameVersion4 = function(callback){
callback.apply(this)
}
}
function niceCallback(){
// Function to be used as callback
var parentObject = this
console.log(parentObject)
}
Now let's create an instance from person constructor and invoke different versions of sayNameVersionX (X refers to 1,2,3,4) method with niceCallback to see how many ways we can manipulate the this inside callback to refer to the person instance.
var p1 = new Person('zami') // Create an instance of Person constructor
bind:
What bind do is to create a new function with the this keyword set to the provided value.
sayNameVersion1 and sayNameVersion2 use bind to manipulate this of the callback function.
this.sayNameVersion1 = function(callback){
callback.bind(this)()
}
this.sayNameVersion2 = function(callback){
callback()
}
The first one binds this with a callback inside the method itself. And for the second one, the callback is passed with the object bound to it.
p1.sayNameVersion1(niceCallback) // pass simply the callback and bind happens inside the sayNameVersion1 method
p1.sayNameVersion2(niceCallback.bind(p1)) // uses bind before passing callback
call:
The first argument of the call method is used as this inside the function that is invoked with call attached to it.
sayNameVersion3 uses call to manipulate the this to refer to the person object that we created, instead of the window object.
this.sayNameVersion3 = function(callback){
callback.call(this)
}
And it is called like the following:
p1.sayNameVersion3(niceCallback)
apply:
Similar to call, the first argument of apply refers to the object that will be indicated by the this keyword.
sayNameVersion4 uses apply to manipulate this to refer to a person object
this.sayNameVersion4 = function(callback){
callback.apply(this)
}
And it is called like the following. Simply the callback is passed,
p1.sayNameVersion4(niceCallback)
We can not bind this to setTimeout(), as it always executes with the global object (Window). If you want to access the this context in the callback function then by using bind() to the callback function, we can achieve it as:
setTimeout(function(){
this.methodName();
}.bind(this), 2000);
The question revolves around how the this keyword behaves in JavaScript. this behaves differently as below,
The value of this is usually determined by a function execution context.
In the global scope, this refers to the global object (the window object).
If strict mode is enabled for any function then the value of this will be undefined as in strict mode, global object refers to undefined in place of the window object.
The object that is standing before the dot is what the this keyword will be bound to.
We can set the value of this explicitly with call(), bind(), and apply()
When the new keyword is used (a constructor), this is bound to the new object being created.
Arrow functions don’t bind this — instead, this is bound lexically (i.e., based on the original context)
As most of the answers suggest, we can use the arrow function or bind() Method or Self var. I would quote a point about lambdas (arrow function) from Google JavaScript Style Guide
Prefer using arrow functions over f.bind(this), and especially over
goog.bind(f, this). Avoid writing const self = this. Arrow functions
are particularly useful for callbacks, which sometimes pass unexpectedly
additional arguments.
Google clearly recommends using lambdas rather than bind or const self = this
So the best solution would be to use lambdas as below,
function MyConstructor(data, transport) {
this.data = data;
transport.on('data', () => {
alert(this.data);
});
}
References:
https://medium.com/tech-tajawal/javascript-this-4-rules-7354abdb274c
arrow-functions-vs-bind
Currently there is another approach possible if classes are used in code.
With support of class fields, it's possible to make it the following way:
class someView {
onSomeInputKeyUp = (event) => {
console.log(this); // This refers to the correct value
// ....
someInitMethod() {
//...
someInput.addEventListener('input', this.onSomeInputKeyUp)
For sure under the hood it's all the old good arrow function that binds context, but in this form it looks much more clear that explicit binding.
Since it's a Stage 3 Proposal, you will need Babel and appropriate Babel plugin to process it as for now (08/2018).
I was facing a problem with Ngx line chart xAxisTickFormatting function which was called from HTML like this: [xAxisTickFormatting]="xFormat".
I was unable to access my component's variable from the function declared. This solution helped me to resolve the issue to find the correct this.
Instead of using the function like this:
xFormat (value): string {
return value.toString() + this.oneComponentVariable; //gives wrong result
}
Use this:
xFormat = (value) => {
// console.log(this);
// now you have access to your component variables
return value + this.oneComponentVariable
}
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 the handleEvent(evt) method from the EventListener interface:
var obj = {
handleEvent(e) {
// always true
console.log(this === obj);
}
};
document.body.addEventListener('click', obj);
Detailed information about using handleEvent can be found here: DOM handleEvent: a cross-platform standard since year 2000
Some other people have touched on how to use the .bind() method, but specifically here is how you can use it with .then() if anyone is having trouble getting them to work together:
someFunction()
.then(function(response) {
//'this' wasn't accessible here before but now it is
}.bind(this))
As mentioned in the comments, an alternative would be to use an arrow function that doesn't have its own 'this' value
someFunction()
.then((response)=>{
//'this' was always accessible here
})
this in JavaScript:
The value of this in JavaScript is 100% determined by how a function is called, and not how it is defined. We can relatively easily find the value of this by the 'left of the dot rule':
When the function is created using the function keyword the value of this is the object left of the dot of the function which is called
If there is no object left of the dot then the value of this inside a function is often the global object (global in Node.js and window in a browser). I wouldn't recommend using the this keyword here because it is less explicit than using something like window!
There exist certain constructs like arrow functions and functions created using the Function.prototype.bind() a function that can fix the value of this. These are exceptions of the rule, but they are really helpful to fix the value of this.
Example in Node.js
module.exports.data = 'module data';
// This outside a function in node refers to module.exports object
console.log(this);
const obj1 = {
data: "obj1 data",
met1: function () {
console.log(this.data);
},
met2: () => {
console.log(this.data);
},
};
const obj2 = {
data: "obj2 data",
test1: function () {
console.log(this.data);
},
test2: function () {
console.log(this.data);
}.bind(obj1),
test3: obj1.met1,
test4: obj1.met2,
};
obj2.test1();
obj2.test2();
obj2.test3();
obj2.test4();
obj1.met1.call(obj2);
Output:
Let me walk you through the outputs one by one (ignoring the first log starting from the second):
this is obj2 because of the left of the dot rule, we can see how test1 is called obj2.test1();. obj2 is left of the dot and thus the this value.
Even though obj2 is left of the dot, test2 is bound to obj1 via the bind() method. The this value is obj1.
obj2 is left of the dot from the function which is called: obj2.test3(). Therefore obj2 will be the value of this.
In this case: obj2.test4() obj2 is left of the dot. However, arrow functions don't have their own this binding. Therefore it will bind to the this value of the outer scope which is the module.exports an object which was logged in the beginning.
We can also specify the value of this by using the call function. Here we can pass in the desired this value as an argument, which is obj2 in this case.
For example.
We have a couple of ES6 module imports, say:
import Module1 from './module_1';
import Module2 from './module_2';
Am using Babel to transpile ES6 into ES5
Have another function, which given a string, returns a reference to the imported ES6 module:
getModule(name) {
switch(name) {
case "Module 1":
return Module1;
case "Module 2":
return Module2;
default:
return null;
}
}
The naming convention is pretty straight forward and consistent
So how to remove the manual switch statement ?
Initially I thought, we can get away with using eval. something like:
getModule(name) {
// removes spaces. so "Module 1" to "Module1"
const ref = name.replace(/\s+/g, "");
return eval(ref);
}
But Babel changes the variable names etc
and has pulled the carpet from under my feet.
Just to demonstrate a non-transpiled example works with:
var foo = function() { console.log("called foo") }
var bar = function() { console.log("called bar") }
eval("foo")() // logs "called foo"
eval("nope") // throws ReferenceError: Can't find variable: nope
Is it possible to get a hash of imports in a file, called say localImports ?
so that we can write:
getModule(name) {
// removes spaces. so "Module 1" to "Module1"
const ref = name.replace(/\s+/g, "");
return localImports[ref];
}
How to implement such a function using ES6 and Babel ?
Also as a bonus, is it possible without using eval ?
This worked for me:
Import the modules.
import Module1 from './module_1';
import Module2 from './module_2';
Cache the modules in local scope with whatever name you want. In this case I use the same name: Module1, Module2.
setModules(){
this.Module1 = Module1;
this.Module2 = Module2;
}
Get the reference to the module using a reference made in local scope.
getModule(name) {
return this[name]; //e.g. name = 'Module1'
}
If you're compiling the imports to require using Babel, you could just use require directly and make a map:
const modules = {
'Module 1': require('./module_1'),
'Module 2': require('./module_2')
};
function getModule(name) {
return modules[name];
}
I have some setup I want during a constructor, but it seems that is not allowed
Which means I can't use:
How else should I do this?
Currently I have something outside like this, but this is not guaranteed to run in the order I want?
async function run() {
let topic;
debug("new TopicsModel");
try {
topic = new TopicsModel();
} catch (err) {
debug("err", err);
}
await topic.setup();
A constructor must return an instance of the class it 'constructs'. Therefore, it's not possible to return Promise<...> and await for it.
You can:
Make your public setup async.
Do not call it from the constructor.
Call it whenever you want to 'finalize' object construction.
async function run()
{
let topic;
debug("new TopicsModel");
try
{
topic = new TopicsModel();
await topic.setup();
}
catch (err)
{
debug("err", err);
}
}
Readiness design pattern
Don't put the object in a promise, put a promise in the object.
Readiness is a property of the object. So make it a property of the object.
The awaitable initialise method described in the accepted answer has a serious limitation. Using await like this means only one block of code can be implicitly contingent on the object being ready. This is fine for code with guaranteed linear execution but in multi-threaded or event driven code it's untenable.
You could capture the task/promise and await that, but how do you manage making this available to every context that depends on it?
The problem is more tractable when correctly framed. The objective is not to wait on construction but to wait on readiness of the constructed object. These are two completely different things. It is even possible for something like a database connection object to be in a ready state, go back to a non-ready state, then become ready again.
How can we determine readiness if it depends on activities that may not be complete when the constructor returns? Quite obviously readiness is a property of the object. Many frameworks directly express the notion of readiness. In JavaScript we have the Promise, and in C# we have the Task. Both have direct language support for object properties.
Expose the construction completion promise as a property of the constructed object. When the asynchronous part of your construction finishes it should resolve the promise.
It doesn't matter whether .then(...) executes before or after the promise resolves. The promise specification states that invoking then on an already resolved promised simply executes the handler immediately.
class Foo {
public Ready: Promise.IThenable<any>;
constructor() {
...
this.Ready = new Promise((resolve, reject) => {
$.ajax(...).then(result => {
// use result
resolve(undefined);
}).fail(reject);
});
}
}
var foo = new Foo();
foo.Ready.then(() => {
// do stuff that needs foo to be ready, eg apply bindings
});
// keep going with other stuff that doesn't need to wait for foo
// using await
// code that doesn't need foo to be ready
await foo.Ready;
// code that needs foo to be ready
Why resolve(undefined); instead of resolve();? Because ES6. Adjust as required to suit your target.
Using await
In a comment it has been suggested that I should have framed this solution with await to more directly address the question as asked.
You can use await with the Ready property as shown in the example above. I'm not a big fan of await because it requires you to partition your code by dependency. You have to put all the dependent code after await and all the independent code before it. This can obscure the intent of the code.
I encourage people to think in terms of call-backs. Mentally framing the problem like this is more compatible with languages like C. Promises are arguably descended from the pattern used for IO completion.
Lack of enforcement as compared to factory pattern
One punter thinks this pattern "is a bad idea because without a factory function, there's nothing to enforce the invariant of checking the readiness. It's left to the clients, which you can practically guarantee will mess up from time to time."
If you take this position then how will you stop people from building factory methods that don't enforce the check? Where do you draw the line? For example, would you forbid the division operator because there's nothing stopping people from passing a zero divisor? The hard truth is you have to learn the difference between domain specific code and framework code and apply different standards, seasoned with some common sense.
Antecedents
This is original work by me. I devised this design pattern because I was unsatisfied with external factories and other such workarounds. Despite searching for some time, I found no prior art for my solution, so I'm claiming credit as the originator of this pattern until disputed.
Nevertheless, in 2020 I discovered that in 2013 Stephen Cleary posted a very similar solution to the problem. Looking back through my own work the first vestiges of this approach appear in code I worked on around the same time. I suspect Cleary put it all together first but he didn't formalise it as a design pattern or publish it where it would be easily found by others with the problem. Moreover, Cleary deals only with construction which is only one application of the Readiness pattern (see below).
Summary
The pattern is
put a promise in the object it describes
expose it as a property named Ready
always reference the promise via the Ready property (don't capture it in a client code variable)
This establishes clear simple semantics and guarantees that
the promise will be created and managed
the promise has identical scope to the object it describes
the semantics of readiness dependence are conspicuous and clear in client code
if the promise is replaced (eg a connection goes unready then ready again due to network conditions) client code referring to it via thing.Ready will always use the current promise
This last one is a nightmare until you use the pattern and let the object manage its own promise. It's also a very good reason to refrain from capturing the promise into a variable.
Some objects have methods that temporarily put them in an invalid condition, and the pattern can serve in that scenario without modification. Code of the form obj.Ready.then(...) will always use whatever promise property is returned by the Ready property, so whenever some action is about to invalidate object state, a fresh promise can be created.
Closing notes
The Readiness pattern isn't specific to construction. It is easily applied to construction but it's really about ensuring that state dependencies are met. In these days of asynchronous code you need a system, and the simple declarative semantics of a promise make it straightforward to express the idea that an action should be taken ASAP, with emphasis on possible. Once you start framing things in these terms, arguments about long running methods or constructors become moot.
Deferred initialisation still has its place; as I mentioned you can combine Readiness with lazy load. But if chances are that you won't use the object, then why create it early? It might be better to create on demand. Or it might not; sometimes you can't tolerate delay between the recognition of need and fulfilment.
There's more than one way to skin a cat. When I write embedded software I create everything up front including resource pools. This makes leaks impossible and memory demands are known at compile time. But that's only a solution for a small closed problem space.
Use an asynchronous factory method instead.
class MyClass {
private mMember: Something;
constructor() {
this.mMember = await SomeFunctionAsync(); // error
}
}
Becomes:
class MyClass {
private mMember: Something;
// make private if possible; I can't in TS 1.8
constructor() {
}
public static CreateAsync = async () => {
const me = new MyClass();
me.mMember = await SomeFunctionAsync();
return me;
};
}
This will mean that you will have to await the construction of these kinds of objects, but that should already be implied by the fact that you are in the situation where you have to await something to construct them anyway.
There's another thing you can do but I suspect it's not a good idea:
// probably BAD
class MyClass {
private mMember: Something;
constructor() {
this.LoadAsync();
}
private LoadAsync = async () => {
this.mMember = await SomeFunctionAsync();
};
}
This can work and I've never had an actual problem from it before, but it seems to be dangerous to me, since your object will not actually be fully initialized when you start using it.
Another way to do it, which might be better than the first option in some ways, is to await the parts, and then construct your object after:
export class MyClass {
private constructor(
private readonly mSomething: Something,
private readonly mSomethingElse: SomethingElse
) {
}
public static CreateAsync = async () => {
const something = await SomeFunctionAsync();
const somethingElse = await SomeOtherFunctionAsync();
return new MyClass(something, somethingElse);
};
}
I've found a solution that looks like
export class SomeClass {
private initialization;
// Implement async constructor
constructor() {
this.initialization = this.init();
}
async init() {
await someAsyncCall();
}
async fooMethod() {
await this.initialization();
// ...some other stuff
}
async barMethod() {
await this.initialization();
// ...some other stuff
}
It works because Promises that powers async/await, can be resolved multiple times with the same value.
I know it's quite old but another option is to have a factory that will create the object and wait for its initialization:
// Declare the class
class A {
// Declare class constructor
constructor() {
// We didn't finish the async job yet
this.initialized = false;
// Simulates async job, it takes 5 seconds to have it done
setTimeout(() => {
this.initialized = true;
}, 5000);
}
// do something usefull here - thats a normal method
useful() {
// but only if initialization was OK
if (this.initialized) {
console.log("I am doing something useful here")
// otherwise throw an error which will be caught by the promise catch
} else {
throw new Error("I am not initialized!");
}
}
}
// factory for common, extensible class - that's the reason for the constructor parameter
// it can be more sophisticated and accept also params for constructor and pass them there
// also, the timeout is just an example, it will wait for about 10s (1000 x 10ms iterations
function factory(construct) {
// create a promise
var aPromise = new Promise(
function(resolve, reject) {
// construct the object here
var a = new construct();
// setup simple timeout
var timeout = 1000;
// called in 10ms intervals to check if the object is initialized
function waiter() {
if (a.initialized) {
// if initialized, resolve the promise
resolve(a);
} else {
// check for timeout - do another iteration after 10ms or throw exception
if (timeout > 0) {
timeout--;
setTimeout(waiter, 10);
} else {
throw new Error("Timeout!");
}
}
}
// call the waiter, it will return almost immediately
waiter();
}
);
// return promise of the object being created and initialized
return a Promise;
}
// this is some async function to create object of A class and do something with it
async function createObjectAndDoSomethingUseful() {
// try/catch to capture exceptions during async execution
try {
// create object and wait until its initialized (promise resolved)
var a = await factory(A);
// then do something usefull
a.useful();
} catch(e) {
// if class instantiation failed from whatever reason, timeout occured or useful was called before the object finished its initialization
console.error(e);
}
}
// now, perform the action we want
createObjectAndDoSomethingUsefull();
// spaghetti code is done here, but async probably still runs
Use a private constructor and a static factory method FTW. It is the best way to enforce any validation logic or data enrichment, encapsulated away from a client.
class Topic {
public static async create(id: string): Promise<Topic> {
const topic = new Topic(id);
await topic.populate();
return topic;
}
private constructor(private id: string) {
// ...
}
private async populate(): Promise<void> {
// Do something async. Access `this.id` and any other instance fields
}
}
// To instantiate a Topic
const topic = await Topic.create();
Use a factory. That's the best practice for these cases.
The problem is that is tricky to define Typescript types for the factory pattern, especially with inheritance.
Let's see how to properly implement it in Typescript.
No inheritance
If you don't need class inheritance, the pattern is this:
class Person {
constructor(public name: string) {}
static async Create(name: string): Promise<Person> {
const instance = new Person(name);
/** Your async code here! **/
return instance;
}
}
const person = await Person.Create('John');
Class inheritance
If you need to extend the class, you will run into a problem. The Create method always returns the base class.
In Typescript, you can fix this with Generic Classes.
type PersonConstructor<T = {}> = new (...args: any[]) => T;
class Person {
constructor(public name: string) {}
static async Create<T extends Person>(
this: PersonConstructor<T>,
name: string,
...args: any[]
): Promise<T> {
const instance = new this(name, ...args);
/** Your async code here! **/
return instance;
}
}
class MyPerson extends Person {
constructor(name: string, public lastName: string) {
super(name);
}
}
const myPerson = await MyPerson.Create('John', 'Snow');
Extending the factory
You can extend the Create method too.
class MyPerson extends Person {
constructor(name: string, public lastName: string) {
super(name);
}
static async Create<T extends Person>(
this: PersonConstructor<T>,
name: string,
lastName: string,
...args: any[]
): Promise<T> {
const instance = await super.Create(name, lastName, ...args);
/** Your async code here! **/
return instance as T;
}
}
const myPerson = await MyPerson.Create('John', 'Snow');
Less verbose alternative
We can reduce the code verbosity by leveraging the async code to a non-static method, which won't require a Generic Class definition when extending the Create method.
type PersonConstructor<T = {}> = new (...args: any[]) => T;
class Person {
constructor(public name: string) {}
protected async init(): Promise<void> {
/** Your async code here! **/
// this.name = await ...
}
static async Create<T extends Person>(
this: PersonConstructor<T>,
name: string,
...args: any[]
): Promise<T> {
const instance = new this(name, ...args);
await instance.init();
return instance;
}
}
class MyPerson extends Person {
constructor(name: string, public lastName: string) {
super(name);
}
override async init(): Promise<void> {
await super.init();
/** Your async code here! **/
// this.lastName = await ...
}
}
const myPerson = await MyPerson.Create('John', 'Snow');
Aren't static methods bad practice?
Yes, with one exception: factories.
Why not return a promise in the constructor?
You can do that, but many will consider your code a bad pattern, because a constructor:
Should always return the class type (Promise<Person> is not Person);
Should never run async code;
You may elect to leave the await out of the equation altogether. You can call it from the constructor if you need to. The caveat being that you need to deal with any return values in the setup/initialise function, not in the constructor.
this works for me, using angular 1.6.3.
import { module } from "angular";
import * as R from "ramda";
import cs = require("./checkListService");
export class CheckListController {
static $inject = ["$log", "$location", "ICheckListService"];
checkListId: string;
constructor(
public $log: ng.ILogService,
public $loc: ng.ILocationService,
public checkListService: cs.ICheckListService) {
this.initialise();
}
/**
* initialise the controller component.
*/
async initialise() {
try {
var list = await this.checkListService.loadCheckLists();
this.checkListId = R.head(list).id.toString();
this.$log.info(`set check list id to ${this.checkListId}`);
} catch (error) {
// deal with problems here.
}
}
}
module("app").controller("checkListController", CheckListController)
Use a setup async method that returns the instance
I had a similar problem in the following case: how to instanciate a 'Foo' class either with an instance of a 'FooSession' class or with a 'fooSessionParams' object, knowing that creating a fooSession from a fooSessionParams object is an async function?
I wanted to instanciate either by doing:
let foo = new Foo(fooSession);
or
let foo = await new Foo(fooSessionParams);
and did'nt want a factory because the two usages would have been too different. But as we know, we can not return a promise from a constructor (and the return signature is different). I solved it this way:
class Foo {
private fooSession: FooSession;
constructor(fooSession?: FooSession) {
if (fooSession) {
this.fooSession = fooSession;
}
}
async setup(fooSessionParams: FooSessionParams): Promise<Foo> {
this.fooSession = await getAFooSession(fooSessionParams);
return this;
}
}
The interesting part is where the setup async method returns the instance itself.
Then if I have a 'FooSession' instance I can use it this way:
let foo = new Foo(fooSession);
And if I have no 'FooSession' instance I can setup 'foo' in one of these ways:
let foo = await new Foo().setup(fooSessionParams);
(witch is my prefered way because it is close to what I wanted first)
or
let foo = new Foo();
await foo.setup(fooSessionParams);
As an alternative I could also add the static method:
static async getASession(fooSessionParams: FooSessionParams): FooSession {
let fooSession: FooSession = await getAFooSession(fooSessionParams);
return fooSession;
}
and instanciate this way:
let foo = new Foo(await Foo.getASession(fooSessionParams));
It is mainly a question of style…
Create holder for promise status:
class MyClass {
constructor(){
this.#fetchResolved = this.fetch()
}
#fetchResolved: Promise<void>;
fetch = async (): Promise<void> => {
return new Promise(resolve => resolve()) // save data to class property or simply add it by resolve() to #fetchResolved reference
}
isConstructorDone = async (): boolean => {
await this.#fetchResolved;
return true; // or any other data depending on constructor finish the job
}
}
To use:
const data = new MyClass();
const field = await data.isConstructorDone();
Or you can just stick to the true ASYNC model and not overcomplicate the setup. 9 out of 10 times this comes down to asynchronous versus synchronous design. For example I have a React component that needed this very same thing were I was initializing the state variables in a promise callback in the constructor. Turns out that all I needed to do to get around the null data exception was just setup an empty state object then set it in the async callback. For example here's a Firebase read with a returned promise and callback:
this._firebaseService = new FirebaseService();
this.state = {data: [], latestAuthor: '', latestComment: ''};
this._firebaseService.read("/comments")
.then((data) => {
const dataObj = data.val();
const fetchedComments = dataObj.map((e: any) => {
return {author: e.author, text: e.text}
});
this.state = {data: fetchedComments, latestAuthor: '', latestComment: ''};
});
By taking this approach my code maintains it's AJAX behavior without compromising the component with a null exception because the state is setup with defaults (empty object and empty strings) prior to the callback. The user may see an empty list for a second but then it's quickly populated. Better yet would be to apply a spinner while the data loads up. Oftentimes I hear of individuals suggesting overly complicated work arounds as is the case in this post but the original flow should be re-examined.