all this  

Coming from a sane language you might think that this in JavaScript is kind of like this in an object oriented language like Java, something that refers to values stored in instance properties. Not so. In JavaScript it is best to think of the this as a boggart carrying a bag of data with an undetectable extension charm.

What follows is what I would want my co-workers to know about using this in JavaScript. It’s a lot and much of it took me years to learn.


 global this

In a browser, at the global scope, this is the window object.

<script type="text/javascript">
console.log(this === window); //true
</script>

jsfiddle

In a browser, using var at the global scope is the same as assigning to this or window.

<script type="text/javascript">
    var foo = "bar";
    console.log(this.foo); //logs "bar"
    console.log(window.foo); //logs "bar"
</script>

jsfiddle

If you create a new variable without using var or let (ECMAScript 6) you are adding or changing a property on the global this.

<script type="text/javascript">
    foo = "bar";

    function testThis() {
      foo = "foo";
    }

    console.log(this.foo); //logs "bar"
    testThis();
    console.log(this.foo); //logs "foo"
</script>

jsfiddle

In node using the repl, this is the top namespace. You can refer to it as global.

> this
{ ArrayBuffer: [Function: ArrayBuffer],
  Int8Array: { [Function: Int8Array] BYTES_PER_ELEMENT: 1 },
  Uint8Array: { [Function: Uint8Array] BYTES_PER_ELEMENT: 1 },
  ...
> global === this
true

In node executing from a script, this at the global scope starts as an empty object. It is not the same as global.

test.js:

console.log(this);
console.log(this === global);
$ node test.js
{}
false

In node, var at the global scope does not assign to this like it does in a browser when you are executing it as a script from a file…

test.js:

var foo = "bar";
console.log(this.foo);
$ node test.js
undefined

…but it does if you’re doing that from the node repl.

> var foo = "bar";
> this.foo
bar
> global.foo
bar

In node, using a script, creating a variable without var or let will add that variable to global but not to the this at the top of the script’s scope.

test.js:

foo = "bar";
console.log(this.foo);
console.log(global.foo);
$ node test.js
undefined
bar

In a node repl, it will assign it to both.


 function this

Except in the case of DOM event handlers or when a thisArg is provided (see further down), both in node and in a browser using this in a function that is not called with new references the global scope…

<script type="text/javascript">
    foo = "bar";

    function testThis() {
      this.foo = "foo";
    }

    console.log(this.foo); //logs "bar"
    testThis();
    console.log(this.foo); //logs "foo"
</script>

jsfiddle

test.js:

foo = "bar";

function testThis () {
  this.foo = "foo";
}

console.log(global.foo);
testThis();
console.log(global.foo);
$ node test.js
bar
foo

…unless you use "use strict"; in which case this will be undefined.

<script type="text/javascript">
    foo = "bar";

    function testThis() {
      "use strict";
      this.foo = "foo";
    }

    console.log(this.foo); //logs "bar"
    testThis();  //Uncaught TypeError: Cannot set property 'foo' of undefined 
</script>

jsfiddle

If you call a function with new the this will be a new context, it will not reference the global this.

<script type="text/javascript">
    foo = "bar";

    function testThis() {
      this.foo = "foo";
    }

    console.log(this.foo); //logs "bar"
    new testThis();
    console.log(this.foo); //logs "bar"

    console.log(new testThis().foo); //logs "foo"
</script>

jsfiddle

I like to call this new context an instance.


 prototype this

Functions you create become function objects. They automatically get a special prototype property, which is something you can assign values to. When you create an instance by calling your function with new you get access to the values you assigned to the prototype property. You access those values using this.

    function Thing() {
      console.log(this.foo);
    }

    Thing.prototype.foo = "bar";

    var thing = new Thing(); //logs "bar"
    console.log(thing.foo);  //logs "bar"

jsfiddle

If you create multiple new instances with new each of these will all share the the same value for values defined on the prototype. For example they will all return the same value when using this.foo unless you override this.foo inside the individual instances.

function Thing() {
}
Thing.prototype.foo = "bar";
Thing.prototype.logFoo = function () {
    console.log(this.foo);
}
Thing.prototype.setFoo = function (newFoo) {
    this.foo = newFoo;
}

var thing1 = new Thing();
var thing2 = new Thing();

thing1.logFoo(); //logs "bar"
thing2.logFoo(); //logs "bar"

thing1.setFoo("foo");
thing1.logFoo(); //logs "foo";
thing2.logFoo(); //logs "bar";

thing2.foo = "foobar";
thing1.logFoo(); //logs "foo";
thing2.logFoo(); //logs "foobar";

jsfiddle

The this in an instance is a special kind of object, this is in fact a key word. You can think of this as a way to access values defined on the prototype, but assigning directly to this inside an instance will hide the value on the prototype from the instance. You can get access back to the prototype value by deleting what you put on this inside the instance…

function Thing() {
}
Thing.prototype.foo = "bar";
Thing.prototype.logFoo = function () {
    console.log(this.foo);
}
Thing.prototype.setFoo = function (newFoo) {
    this.foo = newFoo;
}
Thing.prototype.deleteFoo = function () {
    delete this.foo;
}

var thing = new Thing();
thing.setFoo("foo");
thing.logFoo(); //logs "foo";
thing.deleteFoo();
thing.logFoo(); //logs "bar";
thing.foo = "foobar";
thing.logFoo(); //logs "foobar";
delete thing.foo;
thing.logFoo(); //logs "bar";

jsfiddle

…or just reference the function object’s prototype directly.

function Thing() {
}
Thing.prototype.foo = "bar";
Thing.prototype.logFoo = function () {
    console.log(this.foo, Thing.prototype.foo);
}

var thing = new Thing();
thing.foo = "foo";
thing.logFoo(); //logs "foo bar";

jsfiddle

Instances created with the same function all share access to the same exact values on the prototype. If you assign an array to the prototype all instances are sharing access to that same array. Unless you override it inside the instance in which case you have hidden it.

function Thing() {
}
Thing.prototype.things = [];


var thing1 = new Thing();
var thing2 = new Thing();
thing1.things.push("foo");
console.log(thing2.things); //logs ["foo"]

jsfiddle

It is usually a mistake to assign arrays or objects on the prototype. If you want instances to each have their own arrays, create them in the function, not the prototype.

function Thing() {
    this.things = [];
}


var thing1 = new Thing();
var thing2 = new Thing();
thing1.things.push("foo");
console.log(thing1.things); //logs ["foo"]
console.log(thing2.things); //logs []

jsfiddle

You can actually chain the prototype of many functions together to form a prototype chain so that the special magic of this will walk up the prototype chain until it has found a value you are trying to reference.

function Thing1() {
}
Thing1.prototype.foo = "bar";

function Thing2() {
}
Thing2.prototype = new Thing1();


var thing = new Thing2();
console.log(thing.foo); //logs "bar"

jsfiddle

Some people use this to simulate classical object oriented inheritance in JavaScript.

Any assignments to this in functions used to create the prototype chain will hide values defined further up the prototype chain.

function Thing1() {
}
Thing1.prototype.foo = "bar";

function Thing2() {
    this.foo = "foo";
}
Thing2.prototype = new Thing1();

function Thing3() {
}
Thing3.prototype = new Thing2();


var thing = new Thing3();
console.log(thing.foo); //logs "foo"

jsfiddle

I like to call functions assigned to the prototype “methods”. I used methods in some examples above, like logFoo. These methods get the same magic this prototype lookup as the original function used to create the instance. I usually refer to the original function as the constructor.

The use of this in methods defined on a prototype further up the prototype chain refer to the this of the current instance. This means if you have hidden a value on the prototype chain by assigning to this directly, any of the methods available to the instance will use this new value regardless of what prototype that method was assigned to.

function Thing1() {
}
Thing1.prototype.foo = "bar";
Thing1.prototype.logFoo = function () {
    console.log(this.foo);
}

function Thing2() {
    this.foo = "foo";
}
Thing2.prototype = new Thing1();


var thing = new Thing2();
thing.logFoo(); //logs "foo";

jsfiddle

In JavaScript you can nest functions, that is you can define functions inside functions. While nested functions capture variables defined in parent functions in a closure, they do not inherit the this.

function Thing() {
}
Thing.prototype.foo = "bar";
Thing.prototype.logFoo = function () {
    var info = "attempting to log this.foo:";
    function doIt() {
        console.log(info, this.foo);
    }
    doIt();
}


var thing = new Thing();
thing.logFoo();  //logs "attempting to log this.foo: undefined"

jsfiddle

The this in doIt is the global object or undefined in the case of "use strict"; This is a source of much pain for many people not familiar with this in JavaScript.

It gets worse. Assigning an instance’s method as a value, like say you passed the method as an argument to a function, does not also pass its instance. The this context in a method reverts to a reference to the global object, or undefined in the case of "use strict";, when this happens.

function Thing() {
}
Thing.prototype.foo = "bar";
Thing.prototype.logFoo = function () {  
    console.log(this.foo);   
}

function doIt(method) {
    method();
}


var thing = new Thing();
thing.logFoo(); //logs "bar"
doIt(thing.logFoo); //logs undefined

jsfiddle

Some people prefer to capture this in a variable, usually called “self” and avoid this altogether…

function Thing() {
}
Thing.prototype.foo = "bar";
Thing.prototype.logFoo = function () {
    var self = this;
    var info = "attempting to log this.foo:";
    function doIt() {
        console.log(info, self.foo);
    }
    doIt();
}


var thing = new Thing();
thing.logFoo();  //logs "attempting to log this.foo: bar"

jsfiddle

…but this will not save you in the case you need to pass the method around as a value.

function Thing() {
}
Thing.prototype.foo = "bar";
Thing.prototype.logFoo = function () { 
    var self = this;
    function doIt() {
        console.log(self.foo);
    }
    doIt();
}

function doItIndirectly(method) {
    method();
}


var thing = new Thing();
thing.logFoo(); //logs "bar"
doItIndirectly(thing.logFoo); //logs undefined

jsfiddle

You can pass the instance with the method by using bind, a function defined on the function object for all functions and methods.

function Thing() {
}
Thing.prototype.foo = "bar";
Thing.prototype.logFoo = function () { 
    console.log(this.foo);
}

function doIt(method) {
    method();
}


var thing = new Thing();
doIt(thing.logFoo.bind(thing)); //logs bar

jsfiddle

You can also use apply and call to call the method or function immediately with a new context.

function Thing() {
}
Thing.prototype.foo = "bar";
Thing.prototype.logFoo = function () { 
    function doIt() {
        console.log(this.foo);
    }
    doIt.apply(this);
}

function doItIndirectly(method) {
    method();
}


var thing = new Thing();
doItIndirectly(thing.logFoo.bind(thing)); //logs bar

jsfiddle

You can use bind to replace the this for any function or method, even if it was not assigned to instance’s original prototype.

function Thing() {
}
Thing.prototype.foo = "bar";


function logFoo(aStr) {
    console.log(aStr, this.foo);
}


var thing = new Thing();
logFoo.bind(thing)("using bind"); //logs "using bind bar"
logFoo.apply(thing, ["using apply"]); //logs "using apply bar"
logFoo.call(thing, "using call"); //logs "using call bar"
logFoo("using nothing"); //logs "using nothing undefined"

jsfiddle

You are going to want to avoid returning anything from your constructor, because it may replace what the resulting instance is.

function Thing() {
    return {};
}
Thing.prototype.foo = "bar";


Thing.prototype.logFoo = function () {
    console.log(this.foo);
}


var thing = new Thing();
thing.logFoo(); //Uncaught TypeError: undefined is not a function

jsfiddle

Strangely, if you return a primitive value like a string or a number from a constructor this wont happen and the return statement is ignored. It is best to never return anything from a constructor you intend to call with new even if you know what you are doing. If you want to create a factory pattern, use a function to create instances and don’t call it with new. This advice is only an opinion however.

You can avoid using new and instead use Object.create. This also creates an instance.

function Thing() {
}
Thing.prototype.foo = "bar";


Thing.prototype.logFoo = function () {
    console.log(this.foo);
}


var thing =  Object.create(Thing.prototype);
thing.logFoo(); //logs "bar"

jsfiddle

This will not call the constructor however.

function Thing() {
    this.foo = "foo";
}
Thing.prototype.foo = "bar";


Thing.prototype.logFoo = function () {
    console.log(this.foo);
}


var thing =  Object.create(Thing.prototype);
thing.logFoo(); //logs "bar"

jsfiddle

Because Object.create does not call the constructor it is really useful for creating an inheritance pattern in which you want to override constructors further up the prototype chain.

function Thing1() {
    this.foo = "foo";
}
Thing1.prototype.foo = "bar";

function Thing2() {
    this.logFoo(); //logs "bar"
    Thing1.apply(this);
    this.logFoo(); //logs "foo"
}
Thing2.prototype = Object.create(Thing1.prototype);
Thing2.prototype.logFoo = function () {
    console.log(this.foo);
}

var thing = new Thing2();

jsfiddle


 object this

You can use this in any function on an object to refer to other properties on that object. This is not the same as an instance created with new.

var obj = {
    foo: "bar",
    logFoo: function () {
        console.log(this.foo);
    }
};

obj.logFoo(); //logs "bar"

jsfiddle

Note, there was no use of new , no Object.create and no function called to create obj. You can also bind to objects as if they were an instance.

var obj = {
    foo: "bar"
};

function logFoo() {
    console.log(this.foo);
}

logFoo.apply(obj); //logs "bar"

jsfiddle

There is no walking up the object hierarchy when you use this like this. Only properties shared on the immediate parent object are available via this.

var obj = {
    foo: "bar",
    deeper: {
        logFoo: function () {
            console.log(this.foo);
        }
    }
};

obj.deeper.logFoo(); //logs undefined

jsfiddle

You can just refer to the property you want directly however:

var obj = {
    foo: "bar",
    deeper: {
        logFoo: function () {
            console.log(obj.foo);
        }
    }
};

obj.deeper.logFoo(); //logs "bar"

jsfiddle

 DOM event this

In an HTML DOM event handler, this is always a reference to the DOM element the event was attached to…

function Listener() {
    document.getElementById("foo").addEventListener("click",
       this.handleClick);
}
Listener.prototype.handleClick = function (event) {
    console.log(this); //logs "<div id="foo"></div>"
}

var listener = new Listener();
document.getElementById("foo").click();

jsfiddle

…unless you bind the context.

function Listener() {
    document.getElementById("foo").addEventListener("click", 
        this.handleClick.bind(this));
}
Listener.prototype.handleClick = function (event) {
    console.log(this); //logs Listener {handleClick: function}
}

var listener = new Listener();
document.getElementById("foo").click();

jsfiddle


 HTML this

Inside HTML attributes in which you can put JavaScript, this is a reference to the element.

<div id="foo" onclick="console.log(this);"></div>
<script type="text/javascript">
document.getElementById("foo").click(); //logs <div id="foo"...
</script>

jsfiddle

 override this

You cannot override this as it is a key word.

function test () {
    var this = {};  // Uncaught SyntaxError: Unexpected token this 
}

jsfiddle


 eval this

You can use eval to access this.

function Thing () {
}
Thing.prototype.foo = "bar";
Thing.prototype.logFoo = function () {
    eval("console.log(this.foo)"); //logs "bar"
}

var thing = new Thing();
thing.logFoo();

jsfiddle

This can be a security concern. There is no way to prevent this other than to not use eval.

Functions created with Function also can access this:

function Thing () {
}
Thing.prototype.foo = "bar";
Thing.prototype.logFoo = new Function("console.log(this.foo);");

var thing = new Thing();
thing.logFoo(); //logs "bar"

jsfiddle


 with this

You can use with to add this to the current scope to read and write to values on this without referring to this explicitly.

function Thing () {
}
Thing.prototype.foo = "bar";
Thing.prototype.logFoo = function () {
    with (this) {
        console.log(foo);
        foo = "foo";
    }
}

var thing = new Thing();
thing.logFoo(); // logs "bar"
console.log(thing.foo); // logs "foo"

jsfiddle

Many people believe this is bad because of ambiguity problems with with.


 jQuery this

Like event handlers for HTML DOM elements, the jQuery JavaScript library will in many places have this refer to a DOM element. This is true for event handlers and convenience methods such as $.each.

<div class="foo bar1"></div>
<div class="foo bar2"></div>
<script type="text/javascript">
$(".foo").each(function () {
    console.log(this); //logs <div class="foo...
});
$(".foo").on("click", function () {
    console.log(this); //logs <div class="foo...
});
$(".foo").each(function () {
    this.click();
});
</script>

jsfiddle;

 thisArg this

If you use underscore.js or lo-dash you may know that in many of the library methods you can pass in an instance, via a thisArg function argument that will be used as the context for this. This is true for _.each for example. Native methods found in JavaScript since ECMAScript 5 also allow for a thisArg, like forEach. In fact, the previously demonstrated use of bind, apply and call give you the opportunity to provide a thisArg that when used binds this to the object passed in as the argument.

function Thing(type) {
    this.type = type;
}
Thing.prototype.log = function (thing) {
    console.log(this.type, thing);
}
Thing.prototype.logThings = function (arr) {
   arr.forEach(this.log, this); // logs "fruit apples..."
   _.each(arr, this.log, this); //logs "fruit apples..."
}

var thing = new Thing("fruit");
thing.logThings(["apples", "oranges", "strawberries", "bananas"]);

jsfiddle

This enables code to be a little bit cleaner without many nested bind statements and having to resort to using a “self” variable.


Some programming languages can be simple to learn, for example the specification for the go programming language can be read in a short time. Once the specification has been read, one understands the language, and there are few tricks or gotchas to be troubled about, barring implementation details.

JavaScript is not such a language. The specification is not very readable. There are many “gotchas”, so many in fact that people talk about “The Good Parts.” The best documentation is found on the Mozilla Developer Network. I recommend reading the documentation there about this and to always prefix your Google searches for JavaScript with “mdn” to always get the best documentation. Static code analysis is also great help, for that I use jshint.

If I have made any mistakes or if you have any questions, please let me know I am @bjorntipling on Twitter.

Update:
@hicksyfern has a simpler take that I like in his blog post some of this.

 
2,103
Kudos
 
2,103
Kudos

Now read this

Maps, Sets and Iterators in JavaScript

In my last JavaScript post I wrote about about how to make advanced usage of objects in JavaScript. Continuing in a similar direction, in this post I want look at some new kinds of objects in JavaScript. I will look at maps and sets,... Continue →

Subscribe to Bjorn Tipling

Don’t worry; we hate spam with a passion.
You can unsubscribe with one click.

0obbK04LYREL9i0ib5l