avatarSvetloslav Novoselski

Free AI web copilot to create summaries, insights and extended knowledge, download it at here

10562

Abstract

"hljs-title function_">printActivities</span>(<span class="hljs-params"></span>) { <span class="hljs-variable language_">this</span>.<span class="hljs-property">activities</span>.<span class="hljs-title function_">forEach</span>(<span class="hljs-function"><span class="hljs-params">activity</span> =></span> { <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string"><span class="hljs-subst">${<span class="hljs-variable language_">this</span>.name}</span> loves <span class="hljs-subst">${activity}</span></span>); }); } }; person.<span class="hljs-title function_">printActivities</span>(); <span class="hljs-comment">// Output:</span> <span class="hljs-comment">// Anna loves reading</span> <span class="hljs-comment">// Anna loves hiking</span></pre></div><p id="8fcb">Notice that arrow function in the <code>forEach</code>? It’s comfortably using the <code>this</code> from <code><i>printActivities</i></code>. No drama.</p><p id="23ef"><b>But There’s a Catch</b></p><p id="efad">Arrow functions are a bit stubborn. Methods like <code>call</code>, <code>apply</code>, or <code>bind</code> that we use to set <code>this</code> for regular functions? They don’t work on arrow functions.</p><div id="0db0"><pre><span class="hljs-keyword">const</span> obj = { value: ‘hello’, <span class="hljs-built_in">print</span>: () => { console.log(<span class="hljs-keyword">this</span>.value); } }; <span class="hljs-keyword">const</span> anotherObj = { value: ‘world’ }; obj.<span class="hljs-built_in">print</span>.call(anotherObj); <span class="hljs-comment">// Outputs: undefined</span></pre></div><p id="e933">We tried to be sneaky with <code>call</code>, but the arrow function in <code>print</code> was like, “I know who I am!” and stuck with its original <code>this</code>.</p><p id="a3d8"><b>So, Arrow or Not?</b></p><p id="f1ef">Arrow functions are like that favourite tool you have — super useful, but not right for every job. They’re gold when you want to keep <code>this</code> unchanged, especially in callbacks. But when you need some flexibility? Classic functions might be your friend.</p><h1 id="3884">Inside IIFEs: The Unique Role of “this”</h1><p id="7498">Before we get to the magic of <code>this</code> inside an IIFE, let's clarify what an IIFE is. Picture this: you've just written a function, and before you've even had a chance to sit back and admire your work, it's already doing its thing. That's an IIFE for you!</p><p id="0ad8">An IIFE (Immediately Invoked Function Expression) is like that friend who, right after making a plan, jumps straight into action. As soon as it’s defined, boom — it’s running. And just because it’s speedy doesn’t mean it isn’t versatile. You can craft it with standard functions, arrow functions, and even sprinkle in some async-await magic. Here’s how they look:</p><div id="93f1"><pre><span class="hljs-comment">// The classic way</span> (<span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) { <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(“<span class="hljs-title class_">This</span> is an <span class="hljs-variable constant_">IIFE</span>!”); })();

<span class="hljs-comment">// The modern, arrow function twist</span> (<span class="hljs-function">() =></span> { <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(“<span class="hljs-title class_">Arrow</span> <span class="hljs-keyword">function</span> <span class="hljs-variable constant_">IIFE</span> <span class="hljs-keyword">in</span> action!”); })();

<span class="hljs-comment">// And for those asynchronous adventures</span> (<span class="hljs-keyword">async</span> () => { <span class="hljs-keyword">await</span> <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(“<span class="hljs-title class_">Async</span>-<span class="hljs-keyword">await</span> <span class="hljs-keyword">with</span> <span class="hljs-variable constant_">IIFE</span>? <span class="hljs-title class_">Yep</span>!”); })();</pre></div><p id="a8d7">Now, onto <code>this</code> and its unique dance in IIFEs. When you’re inside an IIFE, and you glance over at <code>this</code>, you're basically looking at the global object. In the browser world, that's our trusty friend, <code>window</code>.</p><div id="6058"><pre>(<span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) { <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-variable language_">this</span>); <span class="hljs-comment">// Outputs: Window {...} in browsers</span> })();</pre></div><p id="f833">But here’s a twist: start your IIFE with the mysterious ‘use strict’; declaration, and <code>this</code> gets an identity crisis. Instead of pointing to the global object, it'll just sit there, being <code>undefined</code>, until you give it some purpose with methods like <code>call</code> or <code>apply</code>.</p><div id="0f20"><pre>(<span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) { <span class="hljs-string">'use strict'</span>; <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-variable language_">this</span>); <span class="hljs-comment">// Outputs: undefined</span> })();</pre></div><h1 id="afff">“this” in Event Handlers: Interacting with the DOM</h1><p id="238d">Let’s paint a picture. You’re on a web page, your favourite song is playing, and there’s a button right there tempting you to click it. Before you know it, the magic of JavaScript comes alive, and things start happening. But have you ever wondered about the inner workings, the hidden puppet strings that make these DOM elements dance? At the heart of this enchantment is our good ol’ friend: <code>this</code>.</p><p id="3bd5"><b>The Main Attraction: Event Listeners</b></p><p id="9869">When you tie an event listener to a DOM element, you’re basically whispering instructions into its ear, telling it, “Hey, when someone interacts with you, do this thing.” And when that ‘thing’ involves the use of <code>this</code>, it generally refers to the element that the event was called upon.</p><div id="8c63"><pre><span class="hljs-keyword">const</span> button = <span class="hljs-variable language_">document</span>.<span class="hljs-title function_">querySelector</span>(‘#myButton’); button.<span class="hljs-title function_">addEventListener</span>(‘click’, <span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) { <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-variable language_">this</span>.<span class="hljs-property">innerHTML</span>); <span class="hljs-comment">// Outputs: whatever text is inside #myButton</span> });</pre></div><p id="c2c1">In this scenario, <code>this</code> is directly pointing to the <code>button</code>. It’s like the button saying, “Yep, I’m the one being clicked!”</p><p id="a104"><b>The Plot Twist: Arrow Functions</b></p><p id="9aec">Now, if you’re tempted to use arrow functions in event listeners, tread lightly. Remember how we discussed that arrow functions inherit <code>this</code> from their surrounding scope? Well, this means they don’t bind their own <code>this</code> like regular functions.</p><div id="3e8c"><pre>button.<span class="hljs-title function_">addEventListener</span>(‘click’, <span class="hljs-function">() =></span> { <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-variable language_">this</span>.<span class="hljs-property">innerHTML</span>); <span class="hljs-comment">// Oops! This won’t work as expected.</span> });</pre></div><p id="8c24">In this setting, <code>this</code> doesn’t point to our button. It might point to the window or another outer scope, leading to unexpected results.</p><p id="f3d0"><b>Dynamic Events: Setting “this” Manually</b></p><p id="0c1f">Sometimes, you need a bit more control, and you might want to dictate what <code>this</code> refers to. For such cases, we’ve got <code>bind</code> to the rescue!</p><div id="9aaf"><pre><span class="hljs-keyword">function</span> <span class="hljs-title function_">displayText</span>(<span class="hljs-params"></span>) { <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-variable language_">this</span>.<span class="hljs-property">innerHTML</span>); } <span class="hljs-keyword">const</span> boundFunction = displayText.<span class="hljs-title function_">bind</span>(button); button.<span class="hljs-title function_">addEventListener</span>(‘click’, boundFunction);</pre></div><p id="8823">Here, no matter where <code>displayText</code> is called from, using <code>bind</code>, we’ve firmly told it to consider <code>button</code> as its <code>this</code>.</p><h1 id="dfcf">“this” in Constructors: Building with Context</h1><p id="d059">Imagine you’re an architect. You’ve got blueprints in hand, materials at the ready, and every time you embark on a new project, you build structures that, while based on a similar design, have their own unique character and identity. In JavaScript, when we talk about constructors, we’re essentially discussing these master blueprints that give rise to individual objects. And, as you might have guessed, <code>this</code> plays a pivotal role in personalizing each of these creations.</p><p id="bfc9"><b>The Foundation: The Constructor Function</b></p><p id="d3b4">At its core, a constructor is just a function. But it’s a function with ambition. It dreams of creating multiple objects, each molded from its framework but holding its own set of values.</p><div id="e63d"><pre><span class="hljs-keyword">function</span> <span class="hljs-title function_">Car</span>(<span class="hljs-params">make, model</span>) { <span class="hljs-variable language_">this</span>.<span class="hljs-property">make</span> = make; <span class="hljs-variable language_">this</span>.<span class="hljs-property">model</span> = model; } <span class="hljs-keyword">const</span> myCar = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Car</span>(‘<span class="hljs-title class_">Toyota</span>’, ‘<span class="hljs-title class_">Corolla</span>’); <span class="hljs-variabl

Options

e language_">console</span>.<span class="hljs-title function_">log</span>(myCar.<span class="hljs-property">make</span>); <span class="hljs-comment">// Outputs: Toyota</span></pre></div><p id="b3b8">Notice how we wield <code>this</code> within the constructor? It’s our way of saying, “For every new car, assign the given make and model to this specific instance.”</p><p id="0d3e"><b>The Spin: Prototype Methods</b></p><p id="f1e7">A perk of using constructors is the ability to attach methods to their prototypes. These methods can access instance-specific data via <code>this</code>, making them quite dynamic.</p><div id="4250"><pre><span class="hljs-title class_">Car</span>.<span class="hljs-property"><span class="hljs-keyword">prototype</span></span>.<span class="hljs-property">displayInfo</span> = <span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) { <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">This car is a <span class="hljs-subst">${<span class="hljs-variable language_">this</span>.make}</span> <span class="hljs-subst">${<span class="hljs-variable language_">this</span>.model}</span>.</span>); }; myCar.<span class="hljs-title function_">displayInfo</span>(); <span class="hljs-comment">// Outputs: This car is a Toyota Corolla.</span></pre></div><p id="0387">Here, the <code>displayInfo</code> method uses <code>this</code> to access the individual car’s make and model, even though the method is shared across instances.</p><p id="b06f"><b>Watch Out: The Arrow Function Trap</b></p><p id="6757">A quick heads-up! Remember our earlier chats about arrow functions? Their behaviour with <code>this</code> remains consistent, even here. So, if you attempt to craft a constructor with an arrow function… well, expect some quirks.</p><div id="b67f"><pre><span class="hljs-keyword">const</span> <span class="hljs-title function_">Gadget</span> = (<span class="hljs-params">name</span>) => { <span class="hljs-variable language_">this</span>.<span class="hljs-property">name</span> = name; } <span class="hljs-comment">// const newGadget = new Gadget(‘Phone’); // This will throw an error!</span></pre></div><p id="8912">In the example above, the arrow function doesn’t create its own <code>this</code>. Instead, it inherits it from its enclosing scope, which can lead to unexpected results when used as a constructor.</p><h1 id="33ff">Common Missteps with “this”: What to Watch For</h1><p id="7ad7">Ah, <code>this</code>! Just when we think we’ve got a handle on it, it throws us a curveball. It’s like trying to hold onto a slippery fish; the moment you lose focus, it’s gone. But fear not! Recognizing the pitfalls is half the battle. Here’s a tour of some common missteps and how to sidestep them.</p><p id="2c29"><b>1. Accidental Global Variables</b></p><p id="3990">This sneaky issue arises when we use <code>this</code> in a regular function without a specific context. If the function isn’t in strict mode, instead of throwing an error, JavaScript will silently bind <code>this</code> to the global object (<code>window</code> in browsers).</p><div id="d4d7"><pre><span class="hljs-keyword">function</span> <span class="hljs-title function_">misstepFunction</span>(<span class="hljs-params"></span>) { <span class="hljs-variable language_">this</span>.<span class="hljs-property">unwantedVar</span> = “<span class="hljs-title class_">Oops</span>!”; } <span class="hljs-title function_">misstepFunction</span>(); <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-variable language_">window</span>.<span class="hljs-property">unwantedVar</span>); <span class="hljs-comment">// Outputs: Oops!</span></pre></div><p id="cf62">📝 <b>Solution:</b> Always use <code>use strict</code> at the beginning of your scripts or functions to prevent such inadvertent assignments.</p><p id="bd62"><b>2. Event Listeners with Object Methods</b></p><p id="0c29">When attaching an object method as an event listener, you might expect <code>this</code> to refer to the object. But, in reality, it often points to the DOM element triggering the event.</p><div id="be02"><pre><span class="hljs-keyword">const</span> buttonController = { <span class="hljs-attr">button</span>: <span class="hljs-variable language_">document</span>.<span class="hljs-title function_">querySelector</span>(‘#myButton’), <span class="hljs-attr">handleClick</span>: <span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) { <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-variable language_">this</span>); <span class="hljs-comment">// Surprise! It’s the button element.</span> } }; buttonController.<span class="hljs-property">button</span>.<span class="hljs-title function_">addEventListener</span>(‘click’, buttonController.<span class="hljs-property">handleClick</span>);</pre></div><p id="e14e">📝 Solution: Use the <code>bind</code> method to explicitly set the value of <code>this</code> or consider wrapping the method call inside another function.</p><p id="9fa7"><b>3. Callbacks with Object Methods</b></p><p id="d430">Similar to event listeners, when passing object methods as callbacks, <code>this</code> can lose its original context.</p><div id="3f7f"><pre><span class="hljs-keyword">const</span> user = { <span class="hljs-attr">name</span>: ‘<span class="hljs-title class_">Alex</span>’, <span class="hljs-attr">greet</span>: <span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) { <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">Hello, <span class="hljs-subst">${<span class="hljs-variable language_">this</span>.name}</span>!</span>); } }; <span class="hljs-built_in">setTimeout</span>(user.<span class="hljs-property">greet</span>, <span class="hljs-number">1000</span>); <span class="hljs-comment">// Outputs: Hello, undefined!</span></pre></div><p id="e61a">📝 <b>Solution: </b>Use an arrow function or bind the method to the object to maintain context: <code>setTimeout(() => user.greet(), 1000)</code>.</p><p id="f76c"><b>4. Arrow Functions in Constructors and Methods</b></p><p id="b924">While arrow functions are incredible, using them for constructor functions or as methods inside objects can lead to undesirable outcomes, thanks to their non-binding nature.</p><div id="5aa9"><pre><span class="hljs-keyword">const</span> <span class="hljs-title function_">Animal</span> = (<span class="hljs-params">name</span>) => { <span class="hljs-variable language_">this</span>.<span class="hljs-property">name</span> = name; <span class="hljs-comment">// Error: Arrow function can’t be used as a constructor.</span> };</pre></div><p id="7ae0">📝 <b>Solution: </b>Stick with regular function declarations for constructors and be cautious about using arrow functions as methods if you intend to utilize <code>this</code>.</p><p id="788e"><b>5. Forgetting “new” with Constructors</b></p><p id="ba6c">If you invoke a constructor function without the <code>new</code> keyword, <code>this</code> won’t point to a fresh object. Instead, it will default to the global object, or if in strict mode, it’ll be undefined.</p><div id="5138"><pre><span class="hljs-keyword">function</span> <span class="hljs-title function_">Book</span>(<span class="hljs-params">title</span>) { <span class="hljs-variable language_">this</span>.<span class="hljs-property">title</span> = title; } <span class="hljs-keyword">const</span> myBook = <span class="hljs-title class_">Book</span>(‘<span class="hljs-title class_">Mystery</span> <span class="hljs-title class_">Tales</span>’); <span class="hljs-comment">// Oops! We forgot ‘new’.</span></pre></div><p id="d618">📝<b> Solution: </b>Always use the <code>new</code> keyword when invoking constructors to ensure proper object creation.</p><h1 id="ba39">Conclusion: Unraveling the Mystery of “this” in JavaScript</h1><p id="58ca">And there we have it — a comprehensive journey through the winding roads of <code>this</code> in JavaScript. If we were to take a step back and reflect on our voyage:</p><ul><li>We began by understanding the <b>fundamental essence</b> of <code>this</code>, its significance, and the initial curiosity it stirs in almost every JavaScript developer.</li><li>Diving deeper, we ventured into the <b>global context</b> and the role <code>this</code> plays there, a serene lake of understanding before plunging into the more turbulent waters.</li><li>We navigated the transformative landscape of <b>regular functions</b>, <b>arrow functions</b>, and <b>IIFEs</b>, seeing the ever-changing face of <code>this</code> in each environment.</li><li>Our exploration was not without its challenges. The <b>DOM</b> presented us with event handlers and their unique relationship with <code>this</code>.</li><li>Diving into the world of <b>constructors</b>, we unearthed how <code>this</code> aids in molding the very building blocks of object-oriented programming in JavaScript.</li><li>To be prepared is to be forewarned. We armed ourselves with knowledge of the <b>common pitfalls</b> of <code>this</code> — those little gremlins lurking in the code, waiting for an opportunity to confound us.</li><li>Stepping out of theory, we waded into <b>practical terrains</b>, where the rubber meets the road. The myriad real-world applications of <code>this</code> shone a light on its true versatility and power.</li></ul><p id="8e21">As we wrap up, remember that every tool, every concept, and every quirk in a programming language has its place. The key lies not just in understanding them but in knowing when, where, and how to use them to the best effect. With <code>this</code> in JavaScript, that rule is no exception. As you move forward in your coding journey, let your newfound knowledge of <code>this</code> be a trusty companion, helping you write code that’s not just functional, but elegant and intuitive.</p><p id="7967">Here’s to clearer skies, smoother coding, and no more mystery around <code>this</code>. Until next time, happy coding! 🚀</p><p id="89f3"><i>Thank you for reading until the end. Please consider following the writer and this publication. Visit <a href="https://stackademic.com/">Stackademic</a> to find out more about how we are democratizing free programming education around the world.</i></p></article></body>

Unlock the Mystery of ‘this’ in JavaScript Once and For All

Introduction: “this” in JavaScript — why it matters

Have you ever felt like JavaScript is playfully challenging you, especially when it waves the this keyword in front of your face? That moment of, “Okay, JavaScript, what game are we playing today?” Especially when you're trying to pin down what this is referencing in a particular piece of code.

Understanding this is like holding a compass in the vast landscape of JavaScript. It's not merely about figuring out a keyword; it's about unlocking doors to advanced coding techniques and patterns.

Why we should care about `this`?

- Ubiquity: Just like that popular tune you can’t escape, this pops up everywhere in JavaScript. From tiny scripts to sprawling web applications, it makes its presence known.

- Leveling Up: Deciphering this means you’re on your way to coding like a seasoned pro. It’s a step closer to more robust and error-free scripts.

- The Chameleon Act: JavaScript, being the versatile language it is, has this dancing to many tunes. It changes its meaning based on its context, making it both intriguing and, occasionally, baffling.

What’s Ahead?

Brace yourself, because we’re about to demystify this, once and for all. We’ll navigate through all its nuances, covering every scenario you might encounter. No more second-guessing or head-scratching!

Ready to dive deep? Whether you’ve been scripting for years or just starting your JavaScript journey, let’s join forces and unravel the mystery of `this` together!

“this” in the Global Context: Getting the Basics

When you’re just starting to understand the this keyword in JavaScript, it’s best to begin at the beginning — and that’s the global context. But what do we mean by the global context?

In simple terms, the global context is the default, top-level environment where your code resides when it’s not inside any function or object. Now, how does this behave here?

In a Browser: If you’re running your JavaScript code in a browser (like most of us often do), this in the global context refers to the window object. This is because, in browsers, the window object is the global object.

console.log(this === window); // true
var variable = “I’m a global variable!”;
console.log(this.variable); // “I’m a global variable!”

Here, when we declare variable, it gets attached to the window object. So, using this.variable in the global context gives us the value of that variable.

In Node.js: If you’re running your code in a Node.js environment, things are a bit different. In Node.js, the top-level value of this is an empty object that’s not equivalent to global.

console.log(this); // {}
global.globalVar = “I’m on the global object in Node!”;
console.log(global.globalVar); // “I’m on the global object in Node!”

It’s essential to understand that the behaviour of this in the global context can vary based on where the code is executed.

So, Why is This Important? Getting to grips with this in the global context provides a foundation for understanding its behaviour in more complex scenarios. As you move deeper into JavaScript, you’ll find situations where functions or methods are invoked from the global context, and understanding this behavior becomes pivotal.

By nailing down the basics, you’re setting yourself up for success as we dive deeper into the intricacies of this in subsequent sections.

“this” inside regular functions: Context is key

Ah, regular functions. They might seem old-school next to their newer arrow function cousins, but they’re still a fundamental part of JavaScript. When it comes to the behaviour of `this` inside these functions, things can get a tad tricky.

Basic Behaviour:

At its core, the value of `this` inside a regular function is determined by how that function is called (its invocation context). Let’s break it down:

Directly Calling a Function:

When you call a function in the global context, this will refer to the global object.

function showThis() {
 console.log(this);
}
showThis(); // ‘window’ in browsers, and ‘global’ in Node.js

As a Method Inside an Object:

When a function is defined as an object method, this will refer to the object that owns the method.

const obj = {
 name: “John”,
 sayName: function() {
 console.log(this.name);
 }
};
obj.sayName(); // “John”

Here, the sayName method is invoked using the obj object. Hence, this inside sayName refers to obj.

Special Cases

Using `call`, `apply`, and `bind`:

These are methods that allow you to directly set what this should refer to, irrespective of how or where a function is called.

- call and apply invoke the function immediately with a specified context.

function greet(greeting) {
 console.log(greeting + ‘, ‘ + this.name);
}
const person = { name: “Alice” };
greet.call(person, “Hello”); // “Hello, Alice”

- bind returns a new function with a bound context but doesn’t execute it immediately.

const boundGreet = greet.bind(person);
boundGreet(“Hi”); // “Hi, Alice”

Why Context Matters?

Understanding how this behaves inside regular functions is all about context. It’s about knowing which object “owns” the function at the point of invocation. This insight can prevent countless bugs and frustrations, especially as your JavaScript projects grow in complexity.

Remember, navigating the intricate maze of JavaScript, the this keyword serves as your beacon of light. In the world of regular functions, it's the context that illuminates the path, ensuring you're always on the right track. As we venture further, observe the dynamic dance between this and context, adjusting to the different rhythms of the language.

Arrow functions and “this”: The Game Changer

Alright, let’s talk arrow functions. When ES6 rolled around, it brought along this snazzy new way of writing functions that not only looked cleaner but also shook up the way we think about `this`.

It’s All About Where You’re From

You know how in life, some of us wear multiple hats depending on where we are and who we’re with? Well, regular functions do something similar with `this`. They can be a bit of a chameleon, changing what `this` refers to based on how they’re called.

Arrow functions, on the other hand? They’re straight shooters. They grab the value of `this` from their surroundings and stick with it. No matter where they go or how they’re used.

const person = {
 name: ‘Anna’,
 activities: [‘reading’, ‘hiking’],
 printActivities() {
 this.activities.forEach(activity => {
 console.log(`${this.name} loves ${activity}`);
 });
 }
};
person.printActivities();
// Output:
// Anna loves reading
// Anna loves hiking

Notice that arrow function in the forEach? It’s comfortably using the this from printActivities. No drama.

But There’s a Catch

Arrow functions are a bit stubborn. Methods like call, apply, or bind that we use to set this for regular functions? They don’t work on arrow functions.

const obj = {
 value: ‘hello’,
 print: () => {
 console.log(this.value);
 }
};
const anotherObj = { value: ‘world’ };
obj.print.call(anotherObj); // Outputs: undefined

We tried to be sneaky with call, but the arrow function in print was like, “I know who I am!” and stuck with its original this.

So, Arrow or Not?

Arrow functions are like that favourite tool you have — super useful, but not right for every job. They’re gold when you want to keep this unchanged, especially in callbacks. But when you need some flexibility? Classic functions might be your friend.

Inside IIFEs: The Unique Role of “this”

Before we get to the magic of this inside an IIFE, let's clarify what an IIFE is. Picture this: you've just written a function, and before you've even had a chance to sit back and admire your work, it's already doing its thing. That's an IIFE for you!

An IIFE (Immediately Invoked Function Expression) is like that friend who, right after making a plan, jumps straight into action. As soon as it’s defined, boom — it’s running. And just because it’s speedy doesn’t mean it isn’t versatile. You can craft it with standard functions, arrow functions, and even sprinkle in some async-await magic. Here’s how they look:

// The classic way
(function () {
 console.log(“This is an IIFE!”);
})();

// The modern, arrow function twist
(() => {
 console.log(“Arrow function IIFE in action!”);
})();

// And for those asynchronous adventures
(async () => {
 await console.log(“Async-await with IIFE? Yep!”);
})();

Now, onto this and its unique dance in IIFEs. When you’re inside an IIFE, and you glance over at this, you're basically looking at the global object. In the browser world, that's our trusty friend, window.

(function () {
    console.log(this);  // Outputs: Window {...} in browsers
})();

But here’s a twist: start your IIFE with the mysterious ‘use strict’; declaration, and this gets an identity crisis. Instead of pointing to the global object, it'll just sit there, being undefined, until you give it some purpose with methods like call or apply.

(function () {
    'use strict';
    console.log(this);  // Outputs: undefined
})();

“this” in Event Handlers: Interacting with the DOM

Let’s paint a picture. You’re on a web page, your favourite song is playing, and there’s a button right there tempting you to click it. Before you know it, the magic of JavaScript comes alive, and things start happening. But have you ever wondered about the inner workings, the hidden puppet strings that make these DOM elements dance? At the heart of this enchantment is our good ol’ friend: this.

The Main Attraction: Event Listeners

When you tie an event listener to a DOM element, you’re basically whispering instructions into its ear, telling it, “Hey, when someone interacts with you, do this thing.” And when that ‘thing’ involves the use of this, it generally refers to the element that the event was called upon.

const button = document.querySelector(‘#myButton’);
button.addEventListener(‘click’, function() {
 console.log(this.innerHTML); // Outputs: whatever text is inside #myButton
});

In this scenario, this is directly pointing to the button. It’s like the button saying, “Yep, I’m the one being clicked!”

The Plot Twist: Arrow Functions

Now, if you’re tempted to use arrow functions in event listeners, tread lightly. Remember how we discussed that arrow functions inherit this from their surrounding scope? Well, this means they don’t bind their own this like regular functions.

button.addEventListener(‘click’, () => {
 console.log(this.innerHTML); // Oops! This won’t work as expected.
});

In this setting, this doesn’t point to our button. It might point to the window or another outer scope, leading to unexpected results.

Dynamic Events: Setting “this” Manually

Sometimes, you need a bit more control, and you might want to dictate what this refers to. For such cases, we’ve got bind to the rescue!

function displayText() {
 console.log(this.innerHTML);
}
const boundFunction = displayText.bind(button);
button.addEventListener(‘click’, boundFunction);

Here, no matter where displayText is called from, using bind, we’ve firmly told it to consider button as its this.

“this” in Constructors: Building with Context

Imagine you’re an architect. You’ve got blueprints in hand, materials at the ready, and every time you embark on a new project, you build structures that, while based on a similar design, have their own unique character and identity. In JavaScript, when we talk about constructors, we’re essentially discussing these master blueprints that give rise to individual objects. And, as you might have guessed, this plays a pivotal role in personalizing each of these creations.

The Foundation: The Constructor Function

At its core, a constructor is just a function. But it’s a function with ambition. It dreams of creating multiple objects, each molded from its framework but holding its own set of values.

function Car(make, model) {
 this.make = make;
 this.model = model;
}
const myCar = new Car(‘Toyota’, ‘Corolla’);
console.log(myCar.make); // Outputs: Toyota

Notice how we wield this within the constructor? It’s our way of saying, “For every new car, assign the given make and model to this specific instance.”

The Spin: Prototype Methods

A perk of using constructors is the ability to attach methods to their prototypes. These methods can access instance-specific data via this, making them quite dynamic.

Car.prototype.displayInfo = function() {
 console.log(`This car is a ${this.make} ${this.model}.`);
};
myCar.displayInfo(); // Outputs: This car is a Toyota Corolla.

Here, the displayInfo method uses this to access the individual car’s make and model, even though the method is shared across instances.

Watch Out: The Arrow Function Trap

A quick heads-up! Remember our earlier chats about arrow functions? Their behaviour with this remains consistent, even here. So, if you attempt to craft a constructor with an arrow function… well, expect some quirks.

const Gadget = (name) => {
 this.name = name;
}
// const newGadget = new Gadget(‘Phone’); // This will throw an error!

In the example above, the arrow function doesn’t create its own this. Instead, it inherits it from its enclosing scope, which can lead to unexpected results when used as a constructor.

Common Missteps with “this”: What to Watch For

Ah, this! Just when we think we’ve got a handle on it, it throws us a curveball. It’s like trying to hold onto a slippery fish; the moment you lose focus, it’s gone. But fear not! Recognizing the pitfalls is half the battle. Here’s a tour of some common missteps and how to sidestep them.

1. Accidental Global Variables

This sneaky issue arises when we use this in a regular function without a specific context. If the function isn’t in strict mode, instead of throwing an error, JavaScript will silently bind this to the global object (window in browsers).

function misstepFunction() {
 this.unwantedVar = “Oops!”;
}
misstepFunction();
console.log(window.unwantedVar); // Outputs: Oops!

📝 Solution: Always use use strict at the beginning of your scripts or functions to prevent such inadvertent assignments.

2. Event Listeners with Object Methods

When attaching an object method as an event listener, you might expect this to refer to the object. But, in reality, it often points to the DOM element triggering the event.

const buttonController = {
 button: document.querySelector(‘#myButton’),
 handleClick: function() {
 console.log(this); // Surprise! It’s the button element.
 }
};
buttonController.button.addEventListener(‘click’, buttonController.handleClick);

📝 Solution: Use the bind method to explicitly set the value of this or consider wrapping the method call inside another function.

3. Callbacks with Object Methods

Similar to event listeners, when passing object methods as callbacks, this can lose its original context.

const user = {
 name: ‘Alex’,
 greet: function() {
 console.log(`Hello, ${this.name}!`);
 }
};
setTimeout(user.greet, 1000); // Outputs: Hello, undefined!

📝 Solution: Use an arrow function or bind the method to the object to maintain context: setTimeout(() => user.greet(), 1000).

4. Arrow Functions in Constructors and Methods

While arrow functions are incredible, using them for constructor functions or as methods inside objects can lead to undesirable outcomes, thanks to their non-binding nature.

const Animal = (name) => {
 this.name = name; // Error: Arrow function can’t be used as a constructor.
};

📝 Solution: Stick with regular function declarations for constructors and be cautious about using arrow functions as methods if you intend to utilize this.

5. Forgetting “new” with Constructors

If you invoke a constructor function without the new keyword, this won’t point to a fresh object. Instead, it will default to the global object, or if in strict mode, it’ll be `undefined`.

function Book(title) {
 this.title = title;
}
const myBook = Book(‘Mystery Tales’); // Oops! We forgot ‘new’.

📝 Solution: Always use the new keyword when invoking constructors to ensure proper object creation.

Conclusion: Unraveling the Mystery of “this” in JavaScript

And there we have it — a comprehensive journey through the winding roads of this in JavaScript. If we were to take a step back and reflect on our voyage:

  • We began by understanding the fundamental essence of this, its significance, and the initial curiosity it stirs in almost every JavaScript developer.
  • Diving deeper, we ventured into the global context and the role this plays there, a serene lake of understanding before plunging into the more turbulent waters.
  • We navigated the transformative landscape of regular functions, arrow functions, and IIFEs, seeing the ever-changing face of this in each environment.
  • Our exploration was not without its challenges. The DOM presented us with event handlers and their unique relationship with this.
  • Diving into the world of constructors, we unearthed how this aids in molding the very building blocks of object-oriented programming in JavaScript.
  • To be prepared is to be forewarned. We armed ourselves with knowledge of the common pitfalls of this — those little gremlins lurking in the code, waiting for an opportunity to confound us.
  • Stepping out of theory, we waded into practical terrains, where the rubber meets the road. The myriad real-world applications of this shone a light on its true versatility and power.

As we wrap up, remember that every tool, every concept, and every quirk in a programming language has its place. The key lies not just in understanding them but in knowing when, where, and how to use them to the best effect. With this in JavaScript, that rule is no exception. As you move forward in your coding journey, let your newfound knowledge of this be a trusty companion, helping you write code that’s not just functional, but elegant and intuitive.

Here’s to clearer skies, smoother coding, and no more mystery around this. Until next time, happy coding! 🚀

Thank you for reading until the end. Please consider following the writer and this publication. Visit Stackademic to find out more about how we are democratizing free programming education around the world.

JavaScript
Javascript Tips
Web Development
Software Development
Software Engineering
Recommended from ReadMedium