this inside function
The this
keyword refers to the object the function belongs to, or the window
object if the function belongs to no object.
It's used in OOP code, to refer to the class/object the function belongs to
For example:
function foo() {
this.value = 'Hello, world';
this.bar = function() {
alert(this.value);
}
}
var inst = new foo();
inst.bar();
This alerts: Hello, world
You can manipulate which object this
refers to by using the apply()
or call()
functions. (A very very handy feature at times)
var bar1 = new function() {
this.value = '#1';
}
var bar2 = new function() {
this.value = '#2';
}
function foo() {
alert(this.value);
}
foo.call(bar1); // Output: #1
foo.apply(bar2, []); // Output: #2
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();
why this inside function refers to global object in node when function itself is not defined on global?
In non-strict mode in Javascript (often called "loose" mode), when you call a function as a regular function such as foo()
, the this
value will be set to the global object.
In strict mode in Javascript, when you call a function as a regular function such as foo()
, the this
value will be set to undefined
.
Based on the results in your question, you are apparently running in non-strict mode so the this
value inside your function is set to the global object when called as foo()
. The function declaration itself in node.js is inside a module so that function has module scope, not global scope and thus the function itself is not a property of the global object. The this
value has only to do with the fact that it was called as foo()
in non-strict mode.
Keep in mind that the this
value in a function in Javascript is entirely determined by how the function was called (and in the case of arrow functions, how it was declared). You can see the six ways that the value of this
is controlled or determined inside a function call here in this answer.
Now, for your specific questions:
this inside a function refers to the object on which function was invoked.
That would be true if the function was called as in obj.foo()
and foo
was defined as a property of object obj
. But, that does not apply when it is called as foo()
and foo
is declared as a stand-alone function (not a property on a specific object).
So from above code I expect foo to exist on global object but that is not the case. Can anyone explain this behaviour?
Whether foo
exists on the global object or not is determined by how foo
is defined, not how it is called. It has to either be specifically assigned to the global object or declared in the global scope. In your specific example in node.js, foo
is declared within module scope (which is actually within a module function) so it is local to that module scope and is not global.
How does this keyword work within a function?
Cannibalized from another post of mine, here's more than you ever wanted to know about this.
Before I start, here's the most important thing to keep in mind about Javascript, and to repeat to yourself when it doesn't make sense. Javascript does not have classes (ES6 class
is syntactic sugar). If something looks like a class, it's a clever trick. Javascript has objects and functions. (that's not 100% accurate, functions are just objects, but it can sometimes be helpful to think of them as separate things)
The this variable is attached to functions. Whenever you invoke a function, this is given a certain value, depending on how you invoke the function. This is often called the invocation pattern.
There are four ways to invoke functions in javascript. You can invoke the function as a method, as a function, as a constructor, and with apply.
As a Method
A method is a function that's attached to an object
var foo = {};
foo.someMethod = function(){
alert(this);
}
When invoked as a method, this will be bound to the object the function/method is a part of. In this example, this will be bound to foo.
As A Function
If you have a stand alone function, the this variable will be bound to the "global" object, almost always the window object in the context of a browser.
var foo = function(){
alert(this);
}
foo();
This may be what's tripping you up, but don't feel bad. Many people consider this a bad design decision. Since a callback is invoked as a function and not as a method, that's why you're seeing what appears to be inconsistent behavior.
Many people get around the problem by doing something like, um, this
var foo = {};
foo.someMethod = function (){
var that=this;
function bar(){
alert(that);
}
}
You define a variable that which points to this. Closure (a topic all its own) keeps that around, so if you call bar as a callback, it still has a reference.
NOTE: In use strict
mode if used as function, this
is not bound to global. (It is undefined
).
As a Constructor
You can also invoke a function as a constructor. Based on the naming convention you're using (TestObject) this also may be what you're doing and is what's tripping you up.
You invoke a function as a Constructor with the new keyword.
function Foo(){
this.confusing = 'hell yeah';
}
var myObject = new Foo();
When invoked as a constructor, a new Object will be created, and this will be bound to that object. Again, if you have inner functions and they're used as callbacks, you'll be invoking them as functions, and this will be bound to the global object. Use that var that = this trick/pattern.
Some people think the constructor/new keyword was a bone thrown to Java/traditional OOP programmers as a way to create something similar to classes.
With the Apply Method
Finally, every function has a method (yes, functions are objects in Javascript) named "apply". Apply lets you determine what the value of this will be, and also lets you pass in an array of arguments. Here's a useless example.
function foo(a,b){
alert(a);
alert(b);
alert(this);
}
var args = ['ah','be'];
foo.apply('omg',args);
Why we cannot access the 'this' inside the inner function?
In the inner function, this
can be referenced, but it has a different value than in the outer function. Every function call involves setting up this
for that particular call inside the called function. Note that it's every function call that determines this
; it's not about the inherent nature of the function, it's about how a function is called.
In this case, the anonymous inner function is called without any explicit value for this
, so its value will be a reference to the global object (window
in a browser). In "strict" mode, the value would be undefined
.
You could force this
to be self
:
(function() {
console.log("inner func: this.foo = " + this.foo);
console.log("inner func: self.foo = " + self.foo);
}.call(self));
By using .call()
, the explicit value for this
inside the anonymous function assures that it will reference the same object.
Why can't I use this inside function?
You have noImplicitThis
compiler option enabled, and in new f
function this
expression implicitly has the type any
- hence the error.
To fix it - just specify the type explicitly using "fake" this
parameter:
const f: any = function(this: typeof target, ...args: any[]) {
// ...
};
By default the type of this inside a function is any. Starting with TypeScript 2.0, you can provide an explicit this parameter. this parameters are fake parameters that come first in the parameter list of a function
using this inside function - nodeJS
The typical solution is to copy this
into another variable called self
.
However, if you aren't going to be creating very many instances of your "class", or it only has a few methods, then it's generally simpler to avoid using constructor functions, this
and new
altogether.
function makeAnObject(username){
// declare private information:
var url = 'url_prefix' + username;
// return public information (usually functions):
return {
loadProfile: function(blah) {
// ...
}
};
};
This lets you have genuinely private data, and you don't have to copy the parameters of makeOnObject
by hand, and you don't have to worry about this
being broken, or remember to prefix calls with new
, etc.
Related Topics
Draggable Line Chart in R/Shiny
How to Parse JavaScript Using Nokogiri and Ruby
How to Disable Browser Developer Tools
Create an Object from an Array of Keys and an Array of Values
Cannot Set Boolean Values in Localstorage
JavaScript Read File Without Using Input
Compare Two JavaScript Arrays and Remove Duplicates
Dynamic Template Urls in Angular 2
How to Remove a Character from a String Using JavaScript
Programmatically Select Text in a Contenteditable HTML Element
Ckeditor 4: Uncaught Typeerror: Cannot Read Property 'Langentries' of Null
Es6 Template Literals VS. Concatenated Strings
Triggering Onclick Event Using Middle Click