Confusions

We’ll soon begin to explain how this actually works, but first we must dispel some misconceptions about how it doesn’t actually work.

The name “this” creates confusion when developers try to think about it too literally. There are two meanings often assumed, but both are incorrect.

Itself

The first common temptation is to assume this refers to the function itself. That’s a reasonable grammatical inference, at least.

Why would you want to refer to a function from inside itself? The most common reasons would be things like recursion (calling a function from inside itself) or having an event handler that can unbind itself when it’s first called.

Developers new to JS’s mechanisms often think that referencing the function as an object (all functions in JavaScript are objects!) lets you store state (values in properties) between function calls. While this is certainly possible and has some limited uses, the rest of the book will expound on many other patterns for better places to store state besides the function object.

But for just a moment, we’ll explore that pattern, to illustrate how this doesn’t let a function get a reference to itself like we might have assumed.

Consider the following code, where we attempt to track how many times a function (foo) was called:

  1. function foo(num) {
  2. console.log( "foo: " + num );
  3. // keep track of how many times `foo` is called
  4. this.count++;
  5. }
  6. foo.count = 0;
  7. var i;
  8. for (i=0; i<10; i++) {
  9. if (i > 5) {
  10. foo( i );
  11. }
  12. }
  13. // foo: 6
  14. // foo: 7
  15. // foo: 8
  16. // foo: 9
  17. // how many times was `foo` called?
  18. console.log( foo.count ); // 0 -- WTF?

foo.count is still 0, even though the four console.log statements clearly indicate foo(..) was in fact called four times. The frustration stems from a too literal interpretation of what this (in this.count++) means.

When the code executes foo.count = 0, indeed it’s adding a property count to the function object foo. But for the this.count reference inside of the function, this is not in fact pointing at all to that function object, and so even though the property names are the same, the root objects are different, and confusion ensues.

Note: A responsible developer should ask at this point, “If I was incrementing a count property but it wasn’t the one I expected, which count was I incrementing?” In fact, were she to dig deeper, she would find that she had accidentally created a global variable count (see Chapter 2 for how that happened!), and it currently has the value NaN. Of course, once she identifies this peculiar outcome, she then has a whole other set of questions: “How was it global, and why did it end up NaN instead of some proper count value?” (see Chapter 2).

Instead of stopping at this point and digging into why the this reference doesn’t seem to be behaving as expected, and answering those tough but important questions, many developers simply avoid the issue altogether, and hack toward some other solution, such as creating another object to hold the count property:

  1. function foo(num) {
  2. console.log( "foo: " + num );
  3. // keep track of how many times `foo` is called
  4. data.count++;
  5. }
  6. var data = {
  7. count: 0
  8. };
  9. var i;
  10. for (i=0; i<10; i++) {
  11. if (i > 5) {
  12. foo( i );
  13. }
  14. }
  15. // foo: 6
  16. // foo: 7
  17. // foo: 8
  18. // foo: 9
  19. // how many times was `foo` called?
  20. console.log( data.count ); // 4

While it is true that this approach “solves” the problem, unfortunately it simply ignores the real problem — lack of understanding what this means and how it works — and instead falls back to the comfort zone of a more familiar mechanism: lexical scope.

Note: Lexical scope is a perfectly fine and useful mechanism; I am not belittling the use of it, by any means (see “Scope & Closures” title of this book series). But constantly guessing at how to use this, and usually being wrong, is not a good reason to retreat back to lexical scope and never learn why this eludes you.

To reference a function object from inside itself, this by itself will typically be insufficient. You generally need a reference to the function object via a lexical identifier (variable) that points at it.

Consider these two functions:

  1. function foo() {
  2. foo.count = 4; // `foo` refers to itself
  3. }
  4. setTimeout( function(){
  5. // anonymous function (no name), cannot
  6. // refer to itself
  7. }, 10 );

In the first function, called a “named function”, foo is a reference that can be used to refer to the function from inside itself.

But in the second example, the function callback passed to setTimeout(..) has no name identifier (so called an “anonymous function”), so there’s no proper way to refer to the function object itself.

Note: The old-school but now deprecated and frowned-upon arguments.callee reference inside a function also points to the function object of the currently executing function. This reference is typically the only way to access an anonymous function’s object from inside itself. The best approach, however, is to avoid the use of anonymous functions altogether, at least for those which require a self-reference, and instead use a named function (expression). arguments.callee is deprecated and should not be used.

So another solution to our running example would have been to use the foo identifier as a function object reference in each place, and not use this at all, which works:

  1. function foo(num) {
  2. console.log( "foo: " + num );
  3. // keep track of how many times `foo` is called
  4. foo.count++;
  5. }
  6. foo.count = 0;
  7. var i;
  8. for (i=0; i<10; i++) {
  9. if (i > 5) {
  10. foo( i );
  11. }
  12. }
  13. // foo: 6
  14. // foo: 7
  15. // foo: 8
  16. // foo: 9
  17. // how many times was `foo` called?
  18. console.log( foo.count ); // 4

However, that approach similarly side-steps actual understanding of this and relies entirely on the lexical scoping of variable foo.

Yet another way of approaching the issue is to force this to actually point at the foo function object:

  1. function foo(num) {
  2. console.log( "foo: " + num );
  3. // keep track of how many times `foo` is called
  4. // Note: `this` IS actually `foo` now, based on
  5. // how `foo` is called (see below)
  6. this.count++;
  7. }
  8. foo.count = 0;
  9. var i;
  10. for (i=0; i<10; i++) {
  11. if (i > 5) {
  12. // using `call(..)`, we ensure the `this`
  13. // points at the function object (`foo`) itself
  14. foo.call( foo, i );
  15. }
  16. }
  17. // foo: 6
  18. // foo: 7
  19. // foo: 8
  20. // foo: 9
  21. // how many times was `foo` called?
  22. console.log( foo.count ); // 4

Instead of avoiding this, we embrace it. We’ll explain in a little bit how such techniques work much more completely, so don’t worry if you’re still a bit confused!

Its Scope

The next most common misconception about the meaning of this is that it somehow refers to the function’s scope. It’s a tricky question, because in one sense there is some truth, but in the other sense, it’s quite misguided.

To be clear, this does not, in any way, refer to a function’s lexical scope. It is true that internally, scope is kind of like an object with properties for each of the available identifiers. But the scope “object” is not accessible to JavaScript code. It’s an inner part of the Engine‘s implementation.

Consider code which attempts (and fails!) to cross over the boundary and use this to implicitly refer to a function’s lexical scope:

  1. function foo() {
  2. var a = 2;
  3. this.bar();
  4. }
  5. function bar() {
  6. console.log( this.a );
  7. }
  8. foo(); //undefined

There’s more than one mistake in this snippet. While it may seem contrived, the code you see is a distillation of actual real-world code that has been exchanged in public community help forums. It’s a wonderful (if not sad) illustration of just how misguided this assumptions can be.

Firstly, an attempt is made to reference the bar() function via this.bar(). It is almost certainly an accident that it works, but we’ll explain the how of that shortly. The most natural way to have invoked bar() would have been to omit the leading this. and just make a lexical reference to the identifier.

However, the developer who writes such code is attempting to use this to create a bridge between the lexical scopes of foo() and bar(), so that bar() has access to the variable a in the inner scope of foo(). No such bridge is possible. You cannot use a this reference to look something up in a lexical scope. It is not possible.

Every time you feel yourself trying to mix lexical scope look-ups with this, remind yourself: there is no bridge.