The Rules of 'this' in JavaScript

Most of the reserved words in JavaScript are pretty self-explanatory; 'if', 'var', 'function', and 'for' do a pretty decent job of indicating their purpose and meaning to people familiar with code and logic. But what about 'this'? The word itself is vague, its meaning seems to change haphazardly, and it is just plain hard to talk about. It feels quite odd to ask, "What is 'this' here? What is the value for this "this'? Are this 'this' and that 'this' the same object?" The concept of 'this' is neither intuitive nor eloquent; it is, however, extremely important for understanding Object Oriented Programming and writing executable, scalable code.

When learning about 'this', what you're really wrapping your head around is the idea of context. Often wrongly confused with scope, context deals with the specific objects that functions can effect at a given time. Depending on where or how a function is invoked, though, 'this' might change. And depending on which style of function you write (ie, ES5 or ES6) 'this' will change, too. And if you're not paying close attention to 'this', you'll quickly end up turning it into the wall-of-text global object, which is definitely not an instance made in your smart little object factory. Thankfully, there is rhyme and reason going on behind the scenes, and the Four Rules of 'This' will make sense of it all.

Rule 1: This, in function code invoked using the new operator, refers to the new instance of that object.

Say you're building out a great new digital pet app, and it requires you to create numerous, mostly-similar instances of a dog object. While it is possible to write a bunch of individual object literals, writing a Class is much more efficient and scalable, and will do all of the repetitive work of creating those objects. And since Classes are merely a JavaScript function in disguise, they just need to be invoked to do the heavy lifting!

No alt text provided for this image

To make a brand new dog object from your Dog class, just use the new operator and call the Dog function. You can pass in whatever details you'd like your new dog to have, and they'll be assigned to the new dog instance. When you need a second, fifteenth, or seventy-second dog object, the Dog class will create each one with whatever set of properties you pass it. All you need is a variable to be assigned to the new dog.

Every time we make a dog object by invoking our Dog class with the new operator, 'this' inside the function refers to the brand new dog instance... and that's how our various combinations of arguments passed for each dog get attached to the correct dog!

Rule 2 - When executing a function as a method on an object, this refers to that object.

So, you've got some fuzzy new dogs. They've got names, favorite toys and maybe some other lovable properties. But dogs have lovable behaviors, too! They wag, sit and run, and JavaScript is ready and waiting to apply those actions to the appropriate dog instances. (Even though it'd be great if all dogs defaulted to wagging all of the time, sometimes they have to nap, so we have to pick and choose which are wagging, and when.)

No alt text provided for this image

To discern which dogs are supposed to be wagging, it's essential that the wag( ) method knows which dog it is acting upon. The code inside wag( ) needs to abide by a clear protocol, and, of course, it has to do with 'this': Each time the wag( ) code is called as a method on a given dog object, the 'this' inside the function block is a reference to that exact dog instance. The ever-changing 'this' allows the method to act on the proper dog.

Rule 3 - The syntax, style, location and nesting levels of the function code surrounding this matters

In our wag( ) method, it is pretty easy to see that wag( ) is set up just like an ES5-style function declaration. The 'function' keyword isn't present, but there are parentheses ready to house parameters that can pass arguments, and curly brackets wrap around the executable code. We know, per Rule 2, that 'this' in a ES5-style function will always refer to the instance that method is being called on. Great!

But what about those fancy ES6-style functions, with their fat arrows? Why do we never, ever see those within a constructor? The answer, as you may have guessed, comes down to how arrow functions handle 'this'.

No alt text provided for this image

Although arrow functions are the newest JavaScript function syntax, that does not mean they were intended to replace the other models. That's definitely not the case! Here's the important difference, relating to 'this': ES5 functions only figure out their context when they're invoked. Not earlier, not later. And ES6 arrow functions operate completely differently: invocation has no effect at all on their context... it was already set, based on where the function was defined in the overall code. Any arrow functions in our Dog class, or any Class, would not have their context updated each time they're invoked. All of the efficiency gained by writing the Class is lost, because you can no longer differentiate which specific dogs should be changed by the methods.

One last interesting note for Rule 3: If you write an arrow function nested within a 'regular' function, the context of the outer function will be set, as always, when it is invoked, and the inner arrow function will inherit that specific context from the outer function. This may create confusing results if you don't understand the subtleties of Rule 3, but could be used strategically when you do. Bottom line: Arrow functions are best left out of Classes and their methods until you feel very comfortable with context.

Rule 4 - Until it is told to do otherwise, this refers to the global object

So there you are, instantiating fuzzy, wagging dogs like crazy. Life feels pretty good. Your code is executing seamlessly, so you stop thinking about 'this' and write a huge list of great new properties and methods for all the unique, new dog objects. Hooray! There are ES5 functions, arrow functions, nested functions, and all of the available combinations of each. Your Class grows from 13 tidy lines to 300 in the blink of an eye.

Before long, though, you start to see that your dog objects aren't being updated when they need to be, and wisely decide to throw a console.log(this) into some of the new methods. You hope to see fuzzy dog instances, but instead, get this:

No alt text provided for this image

It might feel like a giant disaster (with a distinct lack of favorite toys), but really, this is also a predictable behavior in JavaScript. The first line is pretty simple:

{ global:

That's just the beginning of an object literal, and exactly the one you should expect when 'this' has lost its context within a function or method. No problem! Rule 4 tells us that 'this' will default to the global context when it isn't properly assigned to something else. In a browser, that context is always the global window object. You don't need to read through the entire object to get the message, loud and clear: "Go check on 'this'!"

Context might be complex, but it not unpredictable

Like all programming languages, JavaScript does exactly what you tell it to do, and nothing else. As soon as you understand the Four Rules of 'This', you'll be able to easily predict the results your code will produce. After all, we can't spend too much time debugging 'this'... there are so many dogs to play with!


Resources for learning Context and 'this' in JavaScript:

  • "When Not to Use an Arrow Function", wesbos.com/arrow-function-no-no/
  • "JavaScript Arrow Functions and this scoping", wesbos.com/arrow-functions-this-javascript/
  • "What is 'This' in Event Listeners?", metafizzy.co/blog/this-in-event-listeners/
Levi Hoch

Need Programmers? Let's Chat ? Principle Tech Recruiter at TechKru ? Dad

5 年

Very interesting. Thanks for sharing! Did not know that "this" has a different context in arrow functions. I wonder why ??

要查看或添加评论,请登录

Katherine Williams的更多文章

  • Meet Beacon, a search and rescue app

    Meet Beacon, a search and rescue app

    Are you a frequent outdoor adventurer, like me? Ever worry what will happen if you experience an emergency in the…

    7 条评论
  • Customizing your .bash_profile

    Customizing your .bash_profile

    Just before I arrived at the Turing School early in 2019, I diligently followed the Mod 0 instructions to setup my new…

社区洞察

其他会员也浏览了