JavaScript for the C# Guy: The confusion about 'this'


Posted by Shawn Wildermuth on May 28, 2012 on 14:54PM

As a C# guy I am comfortable with the idea of 'this' in the scope of a class (or 'Me' for your VB'ers). It's a relatively simple idea that allows you to access the instance of the class that you're a part of to call members.

In JavaScript that have a similar idea but because of the nature of JavaScript it can cause some odd behavior. Let's look at the standard behavior first.

If we have global code (outside objects or functions) and check the 'this' object, it usually returns the "Window" object in the DOM:

<script type="text/javascript">
  console.log(this.toString()); // Window
                                // unless in strict mode: undefined
</script>

The reason I say that the 'this' keyword returns the "Window" usually is that if you are using strict mode (introduced in ECMA Script 5), then the this keyword is supposed to return undefined. But let's ask the more interesting question, why does this return the "Window" object?

The "Window" object is returned because in the browser, the Window object implements the global object. You can think of the "Window" as implementing the global interface (that's as close as I can map it to C#isms). It has more functionality than just the global objects (e.g. data about the Window) but is a proxy to the global scope.

This behavior changes when you create an object using object syntax in JavaScript:

var obj = {
  name: "hello",

  getThis: function () {
    console.log(this.toString()); // [object object] name = "hello"
    return name;
  } 

};

In this case the 'this' is usually the object itself. Again...that usually word. If you were to have access to the object and call the function, then the 'this' keyword would in fact be the object:

var obj = {
  name: "hello",
  getThis: function () {
    console.log(this.toString()); // [object object] name = "hello"
    return name;
  } 
};
obj.getThis();

This works because the context of the getThis function is the obj object. But since functions are just object types in JavaScript, you can change the scope accidently pretty easily. For example:

var obj = {
  name: "hello",
  getThis: function () {
    console.log(this.toString()); 
    return name;
  }
};
var someFunc = obj.getThis;
someFunc();  // this becomes Window

This happens because the scope of the someFunc function becomes the global scope. It is no longer being executed in the scope of the object. This happens for JavaScript pseudo-classes too:

function MyClass() {
  this.name = "MyClass";
  this.showMe = function () {
    console.log(this.toString()); // [object MyClass]
  };

  return this;
};

var my = new MyClass();
my.showMe(); // this is [object MyClass]

Just like before, when showMe is called, the context of the function is the pseudo-class therefore the 'this' object returns the instance of the MyClass object. But also like before, if you assign the function to a local variable, it executes in a different context:

function MyClass() {
  this.name = "MyClass";
  this.showMe = function () {
    console.log(this.toString()); // [object MyClass]
  };

  return this;
};

var my = new MyClass();

var myFunc = my.showMe;
myFunc(); // 'this' is Window

But we can avoid this behavior with a small piece of code. While creating the pseudo-class our 'this' object is the instance of the class so we can ensure that the function always executes in the context of the instance by binding it to the function:

function MyClass() {
  this.name = "MyClass";
  this.showMe = function () {
    console.log(this.toString()); // [object MyClass]
  }.bind(this);

  return this;
};

var my = new MyClass();

var myFunc = my.showMe;
myFunc(); // 'this' now is [object MyClass]

Whew!  Questions?




Application Name WilderBlog Environment Name Production
Application Ver 1.1.0.0 Runtime Framework .NETCoreApp,Version=v1.1
App Path D:\home\site\wwwroot Runtime Version .NET Core 4.6.24628.01
Operating System Microsoft Windows 6.2.9200 Runtime Arch X86