Welcome to part II of the this keyword discussion. Last time we talked about explicit and implicit bindings. In this post we will discuss lexical and the new keyword.
The new keyword
JavaScript has another pretty cool way to bind the this keyword; using the ‘new’ keyword.
I’m sure you’re familiar with seeing something along the lines of:
var newInstance = new Date();
So what’s with that new keyword anyway? Well to tell you the truth, all it does is create an object; that’s it. Whenever the new keyword is used on a function, JavaScript is on the back-end working it’s magic, creating a new object ( a new instance ). Here, check it out for yourself. Let us demonstrate this with an example.
Open up your web browser’s web-console and within the console, create the following function:
var RedEyeCodingUtil = function(name, lang, day){ this.name = name; this.lang = lang; this.day = day; };
Now invoke the function with the new keyword and assign it to a variable name redEyeCodingVariable (pass in any argument you like) and you can name the variable anything you want:
var redEyeCodingVariable = new RedEyeCodingUtil('JohnDoe', 'JavaScript', 'Saturday');
Next, type out the new variable you created and hit enter; tell the audience what you see:
So now that you have your new object created, what do you think the this keyword will reference? Will it reference the function? Nope. It will reference the new object that the new keyword created.
In our case the this keyword will reference redEyeCodingVariable.
So when you’re in doubt about how to figure out what the this keyword is referencing because you don’t see any implicit or explicit bindings, simply do the following on paper or in your head:
var redEyeCodingVariable = new RedEyeCodingUtil('JohnDoe', 'JavaScript', 'Saturday'); Translate to: var redEyeCodingVariable = {newObject} Tanslate to: //This looks like an implicit bind. Now just look to the left of the dot; that is what this will be referencing. redEyeCodingVariable.RedEyeCodingUtil('JohnDoe', 'JavaScript', 'Saturday')
Now, I don’t know about you, but to me, that lookin a lot like our implicit bind method ( i’m not suggesting that it is an implicit bind, I’m just saying that if we can break it down like we did above, we can easily figure out what this is referencing). So if you really think about it…you can look at it as-if it was an implicit bind ( i.e look to the left of the assignment).
Lexical Scope ( Arrow functions)
this in arrow-functions operates a bit differently than with regular functions. Why? well because they technically don’t have their own this to work with, they inherit their this from the parent scope; a.k.a via lexical-scoping.
Here is an example:
const func1 = function() { console.log('[Regular Function]',this); } const arrow1 = () => {console.log('[Arrow Function]',this)} //Now Lets invoke them both func1(); arrow1();
Let’s checkout the output in console:
Per the capture above, they’re both referencing the global-scope ( Window ). However, the reason’s for doing so are different between the two.
Lets place an arrow function inside an object; as a method..think we’ll get a different result?
let name = 'GLOBAL-SCOPE!'; let arrowObject = { name: 'REDEYECODING', arrow: () => { console.log(this) } }; //Lets invoke: arrowObject.arrow();
Why is this the case? Well because the object that houses arrow-function does not create its own scope separate from the global scope; it belongs to the global-scope, hence the reason for the arrow function’s inheritance of the global scope’s this.
I know the above sounds a little confusing so let me attempt to further explain using another example. Here we set up an arrow function as a method within object1.
let name = 'GLOBAL-SCOPE!'; let object1 = { name: 'LEXICAL-SCOPE', func1 :() => console.log(this.name) }; //Invoked method object1.func1();
Output:
Per the above, object1 doesn’t have it’s own this, so naturally, the arrow function will reference its parent scope ( lexical scope ), which is in this case, the global scope.
Now lets add the arrow function inside another function:
let name = 'GLOBAL-SCOPE!'; let object2 = { name: 'LEXICAL-SCOPE', func2 :function (){ let arrow2 = () => console.log(this.name) return arrow2() } } //Invoked method from Object2 object2.func2()
Output:
Hmm..why is this happening? Well where was the function invoked? It was invoked via the global scope. Ok..but in what context? Let’s look to the left of the dot:
//Invoked method from Object2 object2.func2();
Ok so it was invoked with object2 as the context. Now since object2 has a property of name, based on the implicit method of determining the reference for this, func2 should reference object2’s name , not the global’s name…
So since we know that arrow functions inherit their parent’s this……wait a minute…who is the parent for the arrow function within object2 ?
Ah! Great question! To answer that question, the javascript engine creates a function execution context for all functions, giving each function their own scope; completely separated from the global-execution context, which means there are two separate this’s, one for global and one for the function.
Now let’s continue… since arrow functions inherit their parents this, which in this case is the func2, then that means the arrow function’s this will auto-magically reference the same this information as func2.
I hope this helps.