The parameter in JavaScript is like that oddly concealed obstacle on a path that keeps tripping people. For the JavaScript beginner, it is often a thing of much unclarity, while for many a fairly-seasoned developer, it is one of those things they've figured out how to use but have never understood. this truly The parameter is a vital ingredient in object-oriented JavaScript and a deep understanding of how it behaves is key to unlocking so many other concepts. By the end of this article, you should have gotten the insight needed to forever dispel any uncertainty you may have on subject matter ( ). this this pun so intended What exactly is "this"? When a function is invoked, in addition to the explicit arguments passed to it, it receives other implicit parameters under the hood that are accessible within the body of the function. One of these is the parameter which represents the object that is associated with the function invocation. It is often referred to as the . this function context However, and the way it is determined is one of those things in JavaScript that are not so straightforward. The value of is not only dictated by how and where a function is defined, but also, largely by how it is invoked. To begin making heads or tails of how in a function is determined, we have to revisit our knowledge of function behavior. this this this Invoking functions There are four ways functions can be invoked in JavaScript, each with its own peculiarity: As a function— , in which the function is invoked in a straightforward manner averageJoe() As a method— , which ties the invocation to an object, enabling object-oriented programming averageJoe.talk() As a constructor— , in which a new object is brought into being new AverageJoe() Via the function’s apply or call methods— or averageJoe.call(someObject) averageJoe.apply(someObject) — Secrets of the JavaScript Ninja, Second Edition As a function When a function is invoked in a straightforward manner, its function context (that is, the value) can be two things. In non-strict mode, the global context (the object) becomes the function context. In strict mode, it will be . this window undefined function averageJoe() { console.log(this) } function strictJoe() { "use strict" console.log(this) } averageJoe() // window object strictJoe() // undefined The outcome is the same even if the function is defined within a function, so long it is invoked in a straightforward manner: function outer() { function inner() { console.log(this) } function strictInner() { "use strict" console.log(this) } inner() // window object strictInner() // undefined } outer() As a method Functions can also be properties in objects and in that capacity, they are known as methods. When a function is invoked through an object (as a method), the object itself becomes the function context and is accessible within the body of the method via the parameter. this averageJoe = { name: "Joe", talk: function() { console.log(this) } } averageJoe.talk() // {name: "Joe", talk: ƒ} As a constructor are essentially the same old, run-of-the-mill functions we've been dealing with. As the name implies, we use them to "construct" new objects. To invoke a function as a constructor, we precede the function invocation with the keyword. Constructor functions new When a function is invoked with the keyword, a new object instance is created and provided to the function as its context. Within the function, any reference to is a reference to the newly created object instance. new this function AverageJoe() { console.log(this) // {} 'new object' this.name = "Joe" console.log(this) // {name: "Joe"} } new AverageJoe() Via the apply or call method Functions in JavaScript have access to two inbuilt methods: and . apply call func.apply(thisArg, argArray) func.call(thisArg, arg1, arg2, ...) They allow us invoke a function and explicitly tie it to an object. Any object supplied to the parameter becomes the function context and what is referenced by within the function. thisArg this let averageJoe = { name: "Joe" } function randomGuy() { console.log(this) } randomGuy.call(averageJoe) // {name: "Joe"} Taking a closer look at functions Functions being first-class objects in JavaScript mean they can, among other things, be assigned to things and passed around just like other value types. Of course, being objects, when we do assign or pass them around, what we are actually passing is their reference. This flexibility around functions creates plentiful variety in the manner in which they are applied and used. Let's see how the concepts we've covered so far come into play in some of these scenarios. function loneGuy() { console.log(this) } loneGuy() // window object let averageJoe = { name: "Joe", talk: loneGuy } averageJoe.talk() // {name: "Joe", talk: ƒ} let anotherAverageJoe = { name: "Another Joe", speak: averageJoe.talk } anotherAverageJoe.speak() // {name: "Another Joe", speak: ƒ} let anotherLoneGuy = anotherAverageJoe.speak anotherLoneGuy() // window object anotherLoneGuy.apply(averageJoe) // {name: "Joe", talk: ƒ} averageJoe.talk.call(anotherAverageJoe) // {name: "Another Joe", speak: ƒ} We begin by defining a function that logs the current value of within its function body: loneGuy this function loneGuy() { console.log(this) } When invoked as an ordinary, standalone function, the object is outputted as the value of : window this loneGuy() // window object We go on to create an object that has a method that references the function. When the method is invoked, its parent object, now becomes the value: talk loneGuy talk averageJoe this let averageJoe = { name: "Joe", talk: loneGuy } averageJoe.talk() // {name: "Joe", talk: ƒ} We create another object whose method is a reference to . The method is invoked via its parent object , which is rightly outputted as the value. anotherAverageJoe speak averageJoe.talk speak anotherAverageJoe this let anotherAverageJoe = { name: "Another Joe", speak: averageJoe.talk } anotherAverageJoe.speak() // {name: "Another Joe", speak: ƒ} We create a new variable and pass it a reference to . We go ahead to invoke it in a straightforward manner and sure enough, it gets the object as its value. anotherLoneGuy anotherAverageJoe.speak window this let anotherLoneGuy = anotherAverageJoe.speak anotherLoneGuy() // window object Next, we invoke the newly created via the built-in method and explicitly provide as its function context. Expectedly, it runs and logs as its value. We also invoke via the method and provide as its function context which it duly outputs as its value, despite being a method in . anotherLoneGuy apply averageJoe averageJoe this averageJoe.talk call anotherAverageJoe this averageJoe anotherLoneGuy.apply(averageJoe) // {name: "Joe", talk: ƒ} averageJoe.talk.call(anotherAverageJoe) // {name: "Another Joe", speak: ƒ} From all the passing around and reassigning of our initial function, we can see that whilst where and how a function is defined may have a hand in how its value is arrived at, how it eventually gets invoked is the most determining factor. this The curious case of arrow functions came with ES6 and brought new elegance to how functions were wielded in JavaScript. They discarded some of the syntactic baggage of traditional functions and allowed functions to be expressed more succinctly and lucidly. Arrow functions Arrow function expressions weren't just a syntactic retailoring of traditional functions though. They differed not only in syntax but slightly in behavior as well, one of which being how function context is determined. Arrow functions don’t have their own value. Instead, they remember the value of the parameter at the time of their definition. this this Let's understand this by walking through some code. function randomGuy() { function regularFunc() { console.log(this) } const arrowFunc = () => { console.log(this) } regularFunc() arrowFunc() } randomGuy() // regularFunc –> window object // arrowFunc –> window object let averageJoe = { name: "Joe", talk: randomGuy } averageJoe.talk() // regularFunc –> window object // arrowFunc –> {name: "Joe", talk: ƒ} To begin, we define a function, inside of which we house two other functions—a normal function and an arrow function expression —both of which log the value of inside their respective bodies. randomGuy regularFunc arrowFunc this function randomGuy() { function regularFunc() { console.log(this) } const arrowFunc = () => { console.log(this) } regularFunc() arrowFunc() } We invoke the straightforward way and its function context becomes the object. The code executes beyond the function definitions and reaches the invocation. It is also invoked in a straightforward fashion, thus, it gets the object as its function context as well. Next, is invoked and as an arrow function that doesn't determine its own value, it takes on the value existing at the time it was defined, which was the object. randomGuy window regularFunc window arrowFunc this this window randomGuy() // regularFunc –> window object // arrowFunc –> window object It is vital to understand the nuance here. Even though both functions ended up with the object as their respective values, the reasons were different. For it was because it was invoked in straightforward manner, while for it was because the object was the existing value at the time of its definition and that was what it stuck with. window this regularFunc arrowFunc window this We go on to define an object which has a method that is a reference to . averageJoe talk randomGuy let averageJoe = { name: "Joe", talk: randomGuy } When the method is invoked, the value within its body becomes its parent object through which it was invoked. We go past the function definitions and once again, gets invoked in a straightforward fashion making the object its value. Next, is invoked, and being an arrow function, it remembers the value that existed at the time it was defined (the object) and inherits it as its own value. talk this averageJoe regularFunc window this arrowFunc this averageJoe this averageJoe.talk() // regularFunc –> window object // arrowFunc –> {name: "Joe", talk: ƒ} Arrow functions get their function context from the existing function context at the time of their definition. They remember this context and stick faithfully to it no matter how they're invoked later on. Arrow functions as callbacks An area where the practicality of arrow functions comes to bear is in the use of callback functions. Traditional functions have always been quirky in this regard and prior to arrow functions, developers had to resort to workarounds when using them as callbacks in certain cases. Take a look at this code for example: let averageJoe = { hobbies: ["reading", "coding", "blogging"], printHobby: function(hobby) { console.log(hobby) }, printHobbies: function() { this.hobbies.forEach(function(hobby) { this.printHobby(hobby) }) } } averageJoe.printHobbies() // Uncaught TypeError: this.printHobby is not a function In this scenario, using a traditional function expression as our callback brought us nothing but heartbreak. When the anonymous callback function we passed to the method gets invoked, it takes on the object as its function context and which, of course, isn't where the method resides. Hence, the error we got. forEach window printHobby However, when we make use of an arrow function instead, we see that it captures the prevailing value at the time of its definition (the object) and this, in turn, leads to the output we desire: this averageJoe // ... printHobbies: function() { this.hobbies.forEach(hobby => { this.printHobby(hobby) }) } } averageJoe.printHobbies() // "reading", "coding", "blogging" Using arrow functions as methods You should be a bit careful with arrow functions. Their characteristic of inheriting the parameter leads to a quirk when we use them as methods. this Take this for example: let averageJoe = { name: "Joe", talk: () => { console.log(this) } } averageJoe.talk() // window object Within the method, now references the object as opposed to its parent object . Crazy, right? Don't panic, I will explain. talk this window averageJoe It's actually quite simple. Arrow functions always sticking to the value existing at the time of their definition means that they won't take their parent objects as their function context when they're invoked through them as methods. In this particular case, is created in global JavaScript code (that is, not within a function) where the value of is the object and that is what the arrow function expression used for the method stuck with. this averageJoe this window talk This same behavior of arrow functions leads to a different outcome when we come to constructor functions: function AverageJoe() { this.name = "Joe" this.talk = () => { console.log(this) } } let averageJoe = new AverageJoe() averageJoe.talk() // {name: "Joe", talk: ƒ} As we know, invoking constructor functions with the keyword leads to a new object instance being created and made the function context. So, in essence, the object that we are passing the arrow function to as a method is also the existing function context at the time it was defined and that is what it will stick to whenever it is invoked. new In fact, it is invoked. however averageJoe.talk() // {name: "Joe", talk: ƒ} let loneGuy = averageJoe.talk loneGuy() // {name: "Joe", talk: ƒ} not window object averageJoe.talk.call(window) // {name: "Joe", talk: ƒ} still not window object let anotherLoneGuy = averageJoe.talk.bind(window) anotherLoneGuy() // {name: "Joe", talk: ƒ} lol, still not window object On a quick note, you shouldn't use arrow functions as methods as they aren't fit for that purpose. This was only for demonstration purposes. Conclusion We've covered ample ground on this topic. We started off by getting to know what was. We looked at functions, the variety of ways they are invoked, and how they affect how is determined. We also took a good look at arrow functions and their interesting peculiarities. this this Hopefully, this article has done enough to demystify and help you understand the parameter once and for all. Thanks for reading! this Also Published Here