'this' binding in event handlers
JavaScriptThe short answer
In a regular event handler, this refers to the DOM element that the event listener is attached to. But in arrow functions, this comes from the surrounding scope instead. In React, class component event handlers lose their this binding unless you explicitly bind them.
In vanilla JavaScript
When you attach an event handler using addEventListener, this inside the handler is the element the listener is on.
const button = document.querySelector('button');button.addEventListener('click', function () { console.log(this); // the <button> element this.style.color = 'red'; // works — changes button color});This is implicit binding — the browser calls your function with this set to the element.
But if you use an arrow function, this is different:
const button = document.querySelector('button');button.addEventListener('click', () => { console.log(this); // window (or whatever the outer scope is) this.style.color = 'red'; // does NOT work});Arrow functions do not have their own this. They take this from the scope where they are defined. If you define the arrow function in the global scope, this will be window.
Common problem — losing this in callbacks
Here is a situation you will run into often:
const player = { name: 'John', score: 0, handleClick() { this.score += 1; console.log(`${this.name}: ${this.score}`); },};const button = document.querySelector('button');button.addEventListener('click', player.handleClick);// When clicked: "undefined: NaN"When you pass player.handleClick to addEventListener, it is just passing the function reference. The connection to player is lost. When the browser calls the function, this becomes the button element, not player.
Fix 1: Use bind
button.addEventListener( 'click', player.handleClick.bind(player));Fix 2: Wrap in an arrow function
button.addEventListener('click', () => player.handleClick());Fix 3: Use an arrow function as the method
const player = { name: 'John', score: 0, handleClick: () => { // This won't work either — arrow function in object literal // this is window, not player },};Wait — Fix 3 does not actually work. Arrow functions in object literals take this from the outer scope, not the object. This is a very common mistake.
In React class components
This is one of the most classic React problems. In class components, event handlers lose their this binding:
class Counter extends React.Component { constructor(props) { super(props); this.state = { count: 0 }; } handleClick() { // this is undefined here! this.setState({ count: this.state.count + 1 }); } render() { return ( <button onClick={this.handleClick}> {this.state.count} </button> ); }}When React calls this.handleClick, it calls it as a plain function, so this is undefined (because class bodies run in strict mode).
Fix 1: Bind in constructor
constructor(props) { super(props); this.handleClick = this.handleClick.bind(this);}Fix 2: Use arrow function class property
handleClick = () => { this.setState({ count: this.state.count + 1 });};This is the most common fix you will see. Arrow functions take this from the surrounding scope, which is the class instance.
In React functional components
With functional components and hooks, you do not have this problems at all. Functions defined inside the component are just closures — they access state through the closure, not through this.
function Counter() { const [count, setCount] = useState(0); const handleClick = () => { setCount(count + 1); }; return <button onClick={handleClick}>{count}</button>;}No this, no binding issues. This is one of the reasons the React team moved towards functional components.
Interview Tip
If the interviewer asks about this in event handlers, cover three scenarios: vanilla JavaScript (regular vs arrow functions), React class components (the binding problem), and React functional components (no this issues). This shows you understand the concept across different contexts. If they ask specifically about React, mention that this was one of the pain points with class components that hooks solved.
Why interviewers ask this
Event handling is something you do constantly in frontend development. Interviewers want to see if you understand why event handlers sometimes lose their this context and how to fix it. They also want to know if you understand the difference between regular functions and arrow functions in this context. A candidate who can explain these binding issues clearly shows they have dealt with real-world JavaScript problems.