Explain Codes LogoExplain Codes Logo

What underlies this JavaScript idiom: var self = this?

javascript
closure
this-keyword
event-driven-programming
Nikita BarsukovbyNikita Barsukov·Mar 12, 2025
TLDR

The idiom var self = this; shelters the original this context in callbacks and inner functions where this context might otherwise be skewed. In short, it's a contingency plan to maintain consistent access to the original object's properties and methods.

Example:

function Widget() { var self = this; // 'self' saves the day, holds the original 'this' context self.number = 42; // self holds the number 42 like a secret treasure document.addEventListener('click', function() { console.log(self.number); // 'self' doesn't lose the number, even inside the callback }); }

The moving target: Understanding 'this'

In JavaScript, the this keyword acts like a chameleon, changing its context depending on the function execution context. When a method is acting as an event handler, this refers to event-triggering element, not the original object. Using var self = this;, you create a protective closure that allows inner functions to access outer functions' context.

Potential name clashes: 'self' vs 'window.self'

There's a stumbling block with using self - accidentally referring to window.self in browsers, which points to the window object. As the Master Jedi once said, "Name matters in the galactic world of JavaScript". Hence, var that = this; or var _this = this; is more secure.

The gift of ES6: arrow functions

With ES6, arrow functions came as a boon. They leech this context from the parent scope and not having their own. This often discards the need for self.

function Widget() { this.number = 42; // Life, Universe, and everything document.addEventListener('click', () => { console.log(this.number); // Arrow functions are well-behaved, they keep the original 'this' }); }

Explicit context control: Apply and call

For more direct control, Function.prototype.apply() and Function.prototype.call() allow you to set this context explicitly, being a more clear-cut way of function invocation.

Jquery's understudy: The '.proxy()' function

For those who lean towards library solutions, jQuery offers .proxy(), a utility function that binds context more elegantly, concealing the backstage mess behind a neat curtain.

Closure: Mastering 'self = this;'

Closures sit at the heart of self = this;. A closure is the JavaScript's memory, recalling variables from a function's scope after the function has executed. Through a closure, var self = this; acts like a time-capsule, preserving the present context for future inner functions.

Event-driven programming: 'self' to the rescue

The self = this; pattern gets its spotlight in event-driven programming. It allows an event handler to keep its connection to the object of origin rather than the event-triggering object, ensuring this behaves as expected.

Goals: Readable and maintainable code

Choose a solution that aligns with modern best practices, prioritizing readability and maintainability when working with context.

Visualization

Let's demystify var self = this; using a time-zone analogy.

Home Office (🏠): "Local time, right here! ⏰" Headquarters (🏢): "Got it, home office time!"

Office assigns its own time (this) to a universal clock, 'Self':

var self = this; // 🏠⏰ ➡️🌐⏰ Universal clock 'Self' now reflects home office time

When the go-live day arrives (callback or event) and everyone is working at their own speed:

Launch Day (🚀): "Wait, what's the local time?" Self (🌐⏰): "Don't sweat it! I've got the home office time! 📢"

Through the universal clock 'Self', everyone stays in sync with the home office time, irrespective of local time differences. 🌎➡️🏠⏰➡️🌐⏰➡️⌚

Holding 'this' in the asynchronous world:

In asynchronous JavaScript, managing this effectively becomes a necessity, particularly with promises or async/await. Using self = this or arrow functions wraps this with a protective shield, preventing time-based 'this' context alterations from affecting the original context.

New syntax, same concept: ES6 class fields

Even though self = this sounds old-school, modern JavaScript offers alternatives like class fields and arrow functions in classes for cleaner, more intuitive context solutions:

class Widget { number = 42; handleClick = () => { console.log(this.number); // the new 'classy' way of auto-binding 'this' }; }

Concluding remarks: Mastering 'this'

Understanding the behavior of this is a cornerstone in creating robust JavaScript applications. With this knowledge, developers can prevent unexpected context changes, and sharpen their mastery over the predictability of this.