This in JavaScript | Zell Liew

https://zellwk.com/blog/this/

This is really nice to read

Hire me This in JavaScript 21st Jun 2017 Are you confused by the this keyword in JavaScript? It confuses everyone in the beginning, so don’t worry about it. You’re not alone. But that doesn’t mean you can go on without understanding this forever. It is used so much in JavaScript and in tutorials everywhere that you need to grasp what this is sooner or later. Once you understand this, you’ll realize that it’s much simpler than you think it is. By the end of this article, you would have demystified this for yourself. You’ll know what it is, what it does and how to use it. So, what is this? this is a keyword whose value changes depending on how a function gets called. There six different ways where this can take on new values. They are: this in global context this in object construction this in an object method this in a simple function this in an arrow function this in an event listener You may wonder what this is in each context and why there’s a need to change this in the first place. To answer your question, let look at how this changes in each of the six contexts. This in a global context When this is called outside of any function, in a global context, this defaults to the Window object in the browser. console.log(this) // Window This defaults to window object in browsers This defaults to window object in browsers Usually, you wouldn’t use this in a global context anyway, so the value of this here doesn’t really matter. Let’s move on to the next context. This in object construction When you create a new instance of an object with the new keyword, this refers to the instance. function Human (age) { this.age = age } let greg = new Human(22) let thomas = new Human(24) console.log(greg) // this.age = 22 console.log(thomas) // this.age = 24 This refers to the instance This refers to the instance You can see that greg is an instance of Human in the code above. Now, whenever you reference greg, you won’t accidentally get thomas. So, setting this to be the instance makes perfect sense. Let’s look at a closely related context next – this in an object method. This in an object method Methods are fancy words for functions that are associated with an object, like this: (Note: Methods here are defined with the ES6 object literal shorthand. Check out this article if you’re unsure what it does). let o = { // A method aMethod () {} } this within any method refers to the object itself. let o = { sayThis () { console.log(this) } } o.sayThis() // o this in a method refers to the object itself this refers to the object Since this refers to the object, you can use methods to get the instance of an object, like this: function Human (name) { return { name, getName() { return this.name } } } const zell = new Human(‘Zell’) const vincy = new Human(‘Vincy’) console.log(zell.getName()) // Zell In these two object contexts, you can see that the changed value of this lets you get the right instance, which is the basis for Object-oriented programming. That’s a topic for another day though. Let’s move on to the next context. (But before we move on, here’s a quick signup form if you want to get an article from me every Wednesday). Want to become a better Frontend Developer? Don’t worry if you don’t know where to start. I’ll send you to the perfect place – a library of articles on CSS, JavaScript and Node that FEDs like yourself have found helpful. Each week, I’ll also send you an article to help you improve your FED skills crazy fast. First Name Email Address We use this field to detect spam bots. If you fill this in, you will be marked as a spammer. This in a simple function Simple functions are functions you know extremely well; like the one below. Anonymous functions written in the same form are also considered simple functions. function hello () { // say hello! } On browsers, this is always set to Window in a simple function. The same is true even if you call a simple function in an object method. function simpleFunction () { console.log(this) } const o = { sayThis () { simpleFunction() } } simpleFunction() // Window o.sayThis() // Window Unfortunately, the change in this is unexpected for beginners. They expect this to remain the same within object methods. I got caught in it too. To see why, consider the following code. Here, a this.speakLeet function is executed later within a setTimeout function. const o = { doSomethingLater () { setTimeout(function() { this.speakLeet() // Error }, 1000) }, speakLeet() { console.log(`1337 15 4W350M3`) } } Unfortunately, the code above results in an error. The error occurs because this is set to Window in the setTimeout function. Window does not have a speakLeet method. One quick fix is to create a variable that stores the reference to the this. This variable is often called self or that. const o = { doSomethingLater () { const self = this setTimeout(function() { self.speakLeet() }, 1000) }, speakLeet() { console.log(`1337 15 4W350M3`) } } A second way to fix this problem is to use the new ES6 arrow functions, which brings us to the next context. This in arrow functions this in an arrow function is always the same as this around it (in its immediate scope). So, if you use arrow functions within an object method, the this context stays as the object, not Window. With arrow functions, the speakLeet example could be written in the following way: const o = { doSomethingLater () { setTimeout(() => this.speakLeet(), 1000) }, speakLeet() { console.log(`1337 15 4W350M3`) } } (For more info on arrow functions, read this article) A third way to change the value of this within any function is to use either bind, call or apply. We’ll look at bind later in the article, and call and apply another time. But first, let’s go through the final context — event listeners. This in event listeners this is set to the element that fired the event in an event listener: let button = document.querySelector(‘button’) button.addEventListener(‘click’, function() { console.log(this) // button }) When creating more complex components, you may find yourself creating event listeners within methods. function LeetSpeaker (elem) { return { listenClick () { elem.addEventListener(‘click’, function () { // Do something here }) } } } Since this refers to the element in the event listener, if you need to activate another method, you need to provide a reference to the object with. function LeetSpeaker (elem) { return { listenClick () { const self = this elem.addEventListener(‘click’, function () { self.speakLeet() }) }, speakLeet() { console.log(`1337 15 4W350M3`) } } } Alternatively, you can use an arrow function. If you do so, you can still get the element with event.currentTarget. function LeetSpeaker (elem) { return { listenClick () { elem.addEventListener(‘click’, (e) => { console.log(e.currentTarget) // elem this.speakLeet() }) }, speakLeet() { console.log(`1337 15 4W350M3`) } } } But both methods aren’t good enough to help you remove event listeners when the need arises, both are anonymous functions. To remove an event listener, the callback passed as the second value needs to be a named function: function someFunction () { console.log(‘do something’) // Removes the event listener. document.removeEventListener(‘click’, someFunction) } document.addEventListener(‘click’, someFunction) (Here’s more on callbacks if you need help with them). If you need this to reference the object in an event listener, you need to use bind to manually create a this context. function LeetSpeaker (elem) { return { listenClick () { this.listener = this.speakLeet.bind(this) elem.addEventListener(‘click’, this.listener) }, speakLeet(e) { const elem = e.currentTarget console.log(`1337 15 4W350M3`) elem.removeEventListener(‘click’, this.listener) } } } The code above may confuse you if you’ve don’t understand bind. So, before I show you what is happening, let’s take a detour and understand what bind does. Changing this with bind bind is a method that is present in every function. It allows you to change the this context. This method takes in any number of arguments and returns the bound function. const sayThis = _ => console.log(this) const boundFunc = sayThis.bind(/* arguments…*/) The first parameter you pass into bind becomes this in the bound function. Once you have created a bound function, you can call it anytime you wish: const sayThis = _ => console.log(this) const boundFunc = sayThis.bind({hippy: ‘hipster’}) boundFunc() Bind helps to change this Bind helps to change this The other parameters you pass to bind will be passed as arguments to the original function const sayParams = (…args) => console.log(…args) const boundFunc = sayParams.bind(null, 1, 2, 3, 4, 5) boundFunc() Other params passed to bind become arguments in the function Other params passed to bind become arguments in the function That’s really all you need to know about bind. Now, let’s look back at the code to remove event listeners and dissect what is happening: function LeetSpeaker (elem) { return { listenClick () { // Binds this.speakLeet with a reference to the instance. // Sets bound function to this.listener, so we can remove it later. this.listener = this.speakLeet.bind(this) elem.addEventListener(‘click’, this.listener) }, speakLeet(e) { console.log(`1337 15 4W350M3`) // Gets the element so we can remove the event listener. const elem = e.currentTarget // Removes the event listener. elem.removeEventListener(‘click’, this.listener) } } } Here’s a Codepen for you to see the code in action. And that’s all you need to know about this. Let’s wrap up. Wrapping up this is a crucial keyword in JavaScript. It appears in many JavaScript frameworks, so you have to know what it does. In this article, you learned about the six different contexts where this takes on different values. You also learned how to change the this context with functions like bind. Additionally, you also learned to remove event listeners properly. That’s all you need to know about this. Just master the concepts taught in this article and you won’t ever get confused anymore. If you have any questions, just hit me up in the comments below 🙂 (If you liked this article, I’d appreciate it if you could sh

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.