This Inside Function

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



Leave a reply



Submit