JS "this" and Function References - What is it all about?

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
welcome to this video in this video I want to talk about something or tackle something which I saw in a lot of comments and also in some of my courses that it can be hard to grasp to understand and that is the usage of the this keyword in JavaScript and why it can behave strangely in some cases and it's also that when you call a function or a method sometimes you omit the parentheses after the function name and I want to talk about that queue and explain when you call a function with parentheses and when you use it without these so two important things which I see that they can lead to a lot of confusion hopefully this video can clarify these things now for this video we need a tiny demo project to get started and you can find it attached to this video so to say below the video you'll find a link to a github repository with this very simple dummy project there we got a HTML file with a html5 skeleton in the body I got a button saying add name I got an unordered list with no content but with that ID of names and I'm importing my app.js script which is this script of course in there we got an error which we'll fix of course in this video and besides that we get this code now here I'm using JavaScript classes in case you're not used to using classes in JavaScript you probably know constructor functions constructor functions are normal functions which you can call to create new object and initialize them with some properties and methods so I'm talking about object orientated JavaScript development and we need objects to understand and use the this keyword that is why I opted for the next-gen syntax using that es6 feature of classes now you can also take my es6 course and all my accelerated JavaScript first fewer and more about constructor functions and in the year six course you'll learn about classes here I assume you know what classes do in the end they serve as blueprints for us to create new objects we do that with the new keyword this creates a new object in this case we store it in Gen and then don't do anything with that object then because name generator' which is the blueprint or the class for that object I'm creating has a constructor which gets called when I call new and then the code and here basically just gets a reference to my button by using the button tag as a selector and then I attach the event listener for the click event and then we'll need to fill this blank to tell JavaScript which code to execute when a click occurs then I also get a method in this class here a method is just a function in a class you could say it's called add name and in there I create a new instance off the name field class so I create a new object again I don't do anything with that object but one thing I do is I create here we get a constructor and in that constructor I simply create a new list item I then whoops set some text to that list item the text is the argument I'm getting here essentially the name which I want to output and the name is passed here right now it's always max I'll change this and then I get a reference to my unordered list with that ID selector using that names ID here and I add that name now let's make this work by first of all removing these free question marks and here I obviously want to call add name I want to execute that add name method now for this we already need to use the two things this video is about this and we also need to use or call a function in a special way you could say because here I want to execute add name and you could think we just specify add name like this this would be wrong due to two reasons first of all if we specify like this JavaScript would look for a variable called add name or a function called add name in the scope of this constructor and if it doesn't find it there in the global scope in the overall file you could say in the on the whole window to which this script is attached now we got no add name variable or function in the constructor and we also got anon in the overall file or anywhere else in this app so this will not work and I can prove this to you if we save that and I open my developer tools here and I reload this page we already see add name is not defined because it doesn't find it because a method what we have here is attached to this object so to this class and therefore to the object we create based on the class if we want to tell JavaScript that I want to access function that is attached to the class so to say we need that special this keyword this essentially refers Judah object the code is in so here this line of code is in this object in the name generator so if you want to refer to anything else that is attached to the name generator like at name we need to prepend this and then dot because this essentially gives us access to this object and that we can call methods or access properties on that object with the dot notation so ad name now it calls dysfunction on this object this is how we can use this we're still not there though if I save this and I reload hmm I get max here without me touching that button on the other end if I do click the button nothing happens and we also get no error which makes that super hard to debug of course now the problem we got here is this function gets executed immediately and why is that because I have parentheses here what happens is JavaScript reads that code from top to bottom and it does read and parse that code when the script gets first executed which happens when the browser parses this HTML file and reaches the script import it then immediately goes to the script file and parses dead this is important because this allows us to start our scripts when the page is loaded and load everything into memory and let the browser do its job however as it goes through that file it all defines this line and here what I do is I simply execute a function this is how I execute a function right I use the function name and the fact that it's a method here because it's attached to a class it doesn't change that I use the function or method name I add parentheses I could pass any arguments if that function would accept any and we're done this executes a function the problem is here I don't want to execute it immediately when I wanted to in status I just want to tell JavaScript that it should register this event listener and eventually execute this function when that click occurs so not immediately only when that click occurs and to do that I remove these parentheses so the two parentheses I had after add name if I now save this and I reload we don't see Mac's right from the start but if I click the button now I'm adding my list items now why is that because my right now what I'm doing is I'm just passing a reference to my function so like an address you could say to that event listener so I'm basically just telling JavaScript hey here is the address of the function or method you should execute when they click occurs so that you know where to find it when you need to call it because we don't call that function on our own JavaScript does that so to say the browser does that it does that when the click occurs that is exactly what we're setting up here so we just passed the address to the function with parentheses like this we would execute it immediately we don't want to do that therefore without parentheses we just passed the reference the address of the function to the code which should be aware of it and which should execute it when the time is used so when we click this is the important concept here that we're just passing the reference that we're just passing the address to the function and this is perfectly valid and normal JavaScript code this is no workaround or trick or a hack or anything like that this is a normal way of doing that now this is working now let's tweak that code a little bit because this can actually behave strangely right now it doesn't but it can let's say that in this class here we want to manage a list of names and cycle through these names so we could have something like names and that is an array let's say and in there i got max I got my colleague menu and I got an ax so I got these three names and my idea is that for every click I want to output a different name now to do that I need to get access to my name's an add name because that is ultimately where I pass the name - name field now obviously one easy workaround would be to simply move that constant down there but let's pretend we need that in other places of this name generator class - in that case I want to manage it globally simply like that method is available from anywhere in this class - with this I want to make my name's available from anywhere in this class and therefore I can create a property of field named names and I do this by adding this dot at the beginning and what this does is it's now not a constant or variable anymore instead you could say it's a variable attached to this class a so called property or field so now this names can be used from anywhere inside this class and by the way although only instantiated object there we can call add name because it's part of the class and we can access names because it's part of that class due to that this keyword so this really combines or attaches things to the entire class and therefore to the entire object which gets created and what this allows me to do is I can now access this names down there and now here an add name I'm referring to my array of names which I'm setting up in a constructor and this is how we initialize a property or field in a constructor and how we then use it somewhere else however I of course don't just want to use the entire array down there I want to cycle through my names so add another property and I'll name it current name the names of these properties are of course up to you and I'll set this equal to a number zero because index starts at index zero and I want to start with name first because now what I can do is I can access the first element with this current name so current name is null is zero initially so I access the first element in my array here down there first array element is Max and I passed that name field now of course I want to change current name with every click so after creating the name field I can set current name to current name plus one with that plus plus shortcut we only got three elements in the array so what I want to check here is if this current name is greater than this names length then I need to reset it because then we exceeded the array now actually this is not correct check because the length of this array will be free and I actually already exceeded or exhausted the entire array if current name is two because the index starts at zero if current name is two will have extracted the name Ana so therefore I actually want to convert this to greater than or equal to length length is free and if we incremented current name to free we know we don't have a element for that so let's reset it now let's see if that works if I reload and I click add name hmm I get an error and the error is that I cannot read the property and the find of undefined and it occurs in line 19 now line 19 is this line where I try to use names and current name and do you have any idea what's the issue here now in theory that code should work but now we got a special thing of the this keyword this does not always refer to the surrounding object so to say to the class it's generally what it refers to you could say in most cases but actually this is to find a bit differently in JavaScript this refers to whoever called the function in which you use this so an add name we're using this and now who did call or what's responsible for executing this function this is not this class indirectly it is but not directly directly the responsible thing is our button event here and we can show this by console logging this let's look into this let's see what this is when we execute add name if I click here we see it's the button so the button is this here and that is the case because this event listener and therefore the button is executing our function when we click we pass the address to the function to the button or to the event listener and we say execute the function for us when a click occurs and then this simple first to the button this is how it works in JavaScript it's not always the object in which you write your code it's the thing which calls your code which executes your code you could say and that method gets executed by the button when a click occurs just to prove this if I console.log this in a constructor here then we see there it's referring to the name generator object to the class to the constructor function and that is the case because this code here is not executed by the button or anything like that it's simply parsed by JavaScript from top to bottom and therefore this then refers to the class to the object that surrounds it this can be hard to understand and the end it is just something you can memorize this refers to what's executing the code and here the so here in the constructor the what is executing the code is simply just well here this line in the end this is calling the constructor and therefore here we call the code and this in here refers to the constructor now for add name the button calls add name and this then refers to the button and not to this class anymore on the other hand if we would call add name here directly and not wait for a button click so we executed the constructor here and I reload then you see it works and this actually also refers to the name generator the reason for this is that we again execute the code in the scope of this constructor therefore the constructor and therefore the class is executing this line so this refers to who executed it and that is our constructor and therefore the class this is how this works now how can we change that behavior one way of changing it is to use a special method we can call and that is a method we can call on any function it's the bind function bind actually allows us to tell JavaScript what this should be referring to in the function that will eventually get executed so born still does not immediately execute the function we keep that behavior of just passing the address but we configured a function for the time when it we'll get executed so to say and we do so with the first argument by telling it what should this refer to in the function when it gets executed in the future no matter who executes it and if I find this year I'm telling JavaScript that this incite this method should refer to the same thing this refers to in a constructor and as we just saw with console.log in the constructor this refers to the class and not to the button so here I'm telling JavaScript no matter who executes this add name this inside of that name should always refer to this in the constructor to whatever this is and this and the constructor simply is our class because we're calling our constructor down there this is one way of ensuring that this code down there will work if I now save this and I reload you see I can cycle through my names and output them there and now this works as intended and I know that this can be hard to wrap your head around it's a special thing and in the end if you encounter any issues with you using this and suddenly it doesn't work check if your may be calling your function indirectly through some event listener or anything like that and therefore this and a function that gets executed might not be referring to your object anymore now when our way of solving this by the way is that you pass an anonymous function here and that anonymous function has to be an arrow function let's first of all use a normal anonymous function so I have I define a function in place this function here is not executed immediately it's just a find and it will still be executed by the click listener and in there I can of course call add name this add name like this now this line again will not be executed immediately because this is executed immediately but the code in this function is not instead this code being executed immediately just registers the function in memory and passes it to the event listener so if I save this you see nothing gets rendered so this add name is not executed immediately but clicking on add name gives us another issue that add name this add name is not a function and the reason for this is that again this in here in this anonymous function will not refer to or class but to the button because essentially we just did the same with that before before using bind now when using an anonymous arrow function which is all the next generation JavaScript syntax introduced with es6 then this changes now if I save this in a reload it works and the reason for that is that arrow functions specifically solve that problem of this behaving differently because often you don't want it to behave differently and therefore arrow functions were introduced to basically keep the context of this or the reference of this so if you use an arrow function here this will refer to the exact same thing it would refer to if it were used outside of that arrow function this is the idea behind them and therefore now this and here refers to the constructor now we call ad name on this so on our constructor and therefore in the function in ad name this refers to called it who called it well our constructor so this inside here still refers to our constructor to our class a lot of mind yoga here I guess but really something which helps you a lot once you wrap your head around and really something I also encourage you to just play around with you got the code you got the finished code to below the video and I hope that this was helpful see you in future videos hopefully bye
Info
Channel: Academind
Views: 37,758
Rating: 4.9661632 out of 5
Keywords: javascript, js, this, javascript this, function references, javascript functions, javascript function references, js functions
Id: Pv9flm-80vM
Channel Id: undefined
Length: 20min 19sec (1219 seconds)
Published: Wed Sep 12 2018
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.