Something Like “this”

Few people learn JavaScript as a first programming language. Typically people will start with an object-oriented language such as C#, Java or C++. These languages have a few things in common, such as curly braces, objects, functions, if-statements and loops. Another common feature of object-oriented programming languages is the ‘this’ keyword. It refers to the class which contains the currently executing code.

It can be something of a surprise then when a programmer moves on to JavaScript and discovers that the value returned by ‘this’ is less predictable than expected.

There are five different cases where you might use ‘this’. These include using it in the global namespace, and four different ways of using it inside a function, as described by Douglas Crockford in JavaScript – The Good Parts.

‘this’ in the Global Namespace

In the global namespace, that is, outside of any function, ‘this’ refers to the window object. I don’t see any reason why anyone would want to use ‘this’ in the global namespace, in fact it’s probably a bad idea, nevertheless it can be done and so is worth mentioning for completeness.

Scenario 1 – Method Invocation

In JavaScript (and many other languages) a method is a function which is declared inside of a class or object. Referring to ‘this’ inside of a method refers to the containing object. Therefore in the example below we are alerted with ‘Roberto Martinez’ rather than ‘Howard Kendall’.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Set global variable
var manager = 'Howard Kendall';
 
// 1. Method Invocation
var everton = 
    {
        yearFounded : 1878,
        inEurope : true,
        manager : 'Roberto Martinez',
        getManager : function()
        {
            return this.manager;
        }
    };
 
alert(everton.getManager()); // alerts 'Roberto Martinez'
// Set global variable
var manager = 'Howard Kendall';

// 1. Method Invocation
var everton = 
    {
        yearFounded : 1878,
        inEurope : true,
        manager : 'Roberto Martinez',
        getManager : function()
        {
            return this.manager;
        }
    };

alert(everton.getManager()); // alerts 'Roberto Martinez'

This is the kind of behaviour you would expect coming from an object-oriented background, so no unpleasant surprises here.

Scenario 2 – Function Invocation

Here we are referring to any function which is not declared inside an object. That is, any function which is declared in the global namespace. Using ‘this’ inside such functions actually refers to the global namespace, rather than the containing function. Strange behaviour indeed, and Douglas Crockford actually describes this behaviour as a mistake by the creators of JavaScript. Thus in the example below, we are alerted with ‘Howard Kendall’, rather than ‘Roberto Martinez’.

1
2
3
4
5
6
7
8
9
10
11
// Set global variable
var manager = 'Howard Kendall';
 
// 2. Function Invocation
var getManager = function()
{
    var manager = 'Roberto Martinez';
    return this.manager;    
};
 
alert(getManager()); // alerts 'Howard Kendall'
// Set global variable
var manager = 'Howard Kendall';

// 2. Function Invocation
var getManager = function()
{
    var manager = 'Roberto Martinez';
    return this.manager;    
};

alert(getManager()); // alerts 'Howard Kendall'

So we have established that ‘this’ inside of a method refers to the method’s containing object, and ‘this’ inside of a global function refers to the global namespace. But what is referred to by ‘this’ inside of a function which is declared inside of a method? The answer is – the global namespace, as shown in the example below.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var manager = 'Howard Kendall';
 
var everton = 
    {
        yearFounded : 1878,
        inEurope : true,
        manager : 'Roberto Martinez',
        getManager : function()
        {            
            var innerFunction = function()
            {
                return this.manager;
            };            
            return innerFunction();
        }
    };
 
alert(everton.getManager()); // alerts 'Howard Kendall'
var manager = 'Howard Kendall';

var everton = 
    {
        yearFounded : 1878,
        inEurope : true,
        manager : 'Roberto Martinez',
        getManager : function()
        {            
            var innerFunction = function()
            {
                return this.manager;
            };            
            return innerFunction();
        }
    };

alert(everton.getManager()); // alerts 'Howard Kendall'

This behaviour is slightly surprising. If we want to use an inner function inside of a method, we can get around the problem by assigning ‘this’ to a variable inside the outer method, as shown below with the ‘that’ variable.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
var manager = 'Howard Kendall';
 
var everton = 
    {
        yearFounded : 1878,
        inEurope : true,
        manager : 'Roberto Martinez',
        getManager : function()
        {
            var that = this;
            
            var innerFunction = function()
            {
                return that.manager;
            };
            
            return innerFunction();
        }
    };
 
alert(everton.getManager()); // alerts 'Roberto Martinez'
var manager = 'Howard Kendall';

var everton = 
    {
        yearFounded : 1878,
        inEurope : true,
        manager : 'Roberto Martinez',
        getManager : function()
        {
            var that = this;
            
            var innerFunction = function()
            {
                return that.manager;
            };
            
            return innerFunction();
        }
    };

alert(everton.getManager()); // alerts 'Roberto Martinez'

Scenario 3 – Constructor Invocation

A third function scenario is that of the constructor function, that is, a function which is invoked with the ‘new’ keyword. When a function is invoked in this way, the ‘this’ keyword refers to the object created, even if the constructor function was defined in the global namespace. Therefore, in the example below we are alerted first with ‘Howard Kendall’ and then with ‘Joe Royle’. We refer to ‘this’ inside of a global namespace function when we set the ‘manager’ variable inside of ‘getEverton’, but as we call the function with the ‘new’ keyword, the global namespace ‘manager’ variable is not updated.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var manager = 'Howard Kendall';
 
// 3. Constructor Invocation
var getEverton = function()
{
    this.yearFounded = 1878;
    this.inEurope = true;
    this.manager = 'Joe Royle'; 
    
    this.getManager = function()
    {
        return this.manager;
    };
};
 
var efc = new getEverton();
alert(manager); // alerts Howard Kendall
alert(efc.getManager()); // alerts Joe Royle
var manager = 'Howard Kendall';

// 3. Constructor Invocation
var getEverton = function()
{
    this.yearFounded = 1878;
    this.inEurope = true;
    this.manager = 'Joe Royle'; 
    
    this.getManager = function()
    {
        return this.manager;
    };
};

var efc = new getEverton();
alert(manager); // alerts Howard Kendall
alert(efc.getManager()); // alerts Joe Royle

The same behaviour is displayed when we call a method declared on the constructor function’s prototype, and properties can be set on our new object in the normal way.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 3. Constructor Invocation
var getEverton = function()
{
    this.yearFounded = 1878;
    this.inEurope = true;
    this.manager = 'Joe Royle';    
};
 
var efc = new getEverton();
getEverton.prototype.getManager = function()
{
    return this.manager;
};
    
alert(efc.getManager()); // alerts 'Joe Royle'
 
var efc2 = new getEverton();
efc2.manager = 'Harry Catterick';
alert(efc2.getManager()); // alerts 'Harry Catterick'
// 3. Constructor Invocation
var getEverton = function()
{
    this.yearFounded = 1878;
    this.inEurope = true;
    this.manager = 'Joe Royle';    
};

var efc = new getEverton();
getEverton.prototype.getManager = function()
{
    return this.manager;
};
    
alert(efc.getManager()); // alerts 'Joe Royle'

var efc2 = new getEverton();
efc2.manager = 'Harry Catterick';
alert(efc2.getManager()); // alerts 'Harry Catterick'

So to summarise constructor invocation, it reflects typical object-oriented behaviour more closely that function invocation. However, it can be dangerous to rely on this approach, as if we forget to use the ‘new’ keyword, our constructor function will be invoked as a regular global function, and we will see the behaviour described above in scenario 2.

Scenario 4 – Apply Invocation

Our final function invocation scenario is the apply invocation pattern. The apply method is defined on the function prototype, therefore it can be invoked on any function. This approach to invocation allows us to provide any object we want to represent ‘this’ inside of the function. Its first argument is bound to ‘this’, and its second argument is an optional array of parameters to be passed to the function. Thus in the example below, we are first alerted with ‘Joe Royle’ and then with ‘Harry Catterick’.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
var everton = 
    {
        yearFounded : 1878,
        inEurope : true,
        manager : 'Roberto Martinez',
        getManager : function()
        {
            return this.manager;
        }
    };
 
var getEverton = function()
{
    this.manager = 'Joe Royle';    
};
 
var efc = new getEverton();
var efc2 = new getEverton();
efc2.manager = 'Harry Catterick';    
 
// 4. apply() Invocation
alert(everton.getManager.apply(efc)); // alerts 'Joe Royle'
alert(everton.getManager.apply(efc2)); // alerts 'Harry Catterick'
var everton = 
    {
        yearFounded : 1878,
        inEurope : true,
        manager : 'Roberto Martinez',
        getManager : function()
        {
            return this.manager;
        }
    };

var getEverton = function()
{
    this.manager = 'Joe Royle';    
};

var efc = new getEverton();
var efc2 = new getEverton();
efc2.manager = 'Harry Catterick';    

// 4. apply() Invocation
alert(everton.getManager.apply(efc)); // alerts 'Joe Royle'
alert(everton.getManager.apply(efc2)); // alerts 'Harry Catterick'

I have attempted here to clearly describe the different behaviours you might see when using the ‘this’ keyword in JavaScript. However, it is a difficult area to describe in plain english. If you find my descriptions confusing I recommend reading Crockford’s book. All the code examples are available to play with at this jsfiddle.

Share Button
  • Pingback: The Morning Brew - Chris Alcock » The Morning Brew #1672()

  • Yaroslav Yakovlev

    For some reason it doesnt work in jsfiddle: http://jsfiddle.net/yaroslavya/0zgds650/
    It seems variable assignment are not adding properties to window. Same thing works fine in js console and in, say codepen.io. Any ideas why it is like so?

    • http://www.theproactiveprogrammer.com/ Ronnie Mukherjee

      Hi Yaroslav,

      Yes, for some reason in jsfiddle you need to explicitly use ‘this’ to add a variable to the global namespace. As you correctly say you wouldn’t normally have to do this.

      Ronnie