'this' binding in event handlers
The 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.
1const button = document.querySelector('button');23button.addEventListener('click', function () {4 console.log(this); // the <button> element5 this.style.color = 'red'; // works — changes button color6});
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:
1const button = document.querySelector('button');23button.addEventListener('click', () => {4 console.log(this); // window (or whatever the outer scope is)5 this.style.color = 'red'; // does NOT work6});
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:
1const player = {2 name: 'John',3 score: 0,4 handleClick() {5 this.score += 1;6 console.log(`${this.name}: ${this.score}`);7 },8};910const button = document.querySelector('button');11button.addEventListener('click', player.handleClick);12// 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
1button.addEventListener(2 'click',3 player.handleClick.bind(player)4);
Fix 2: Wrap in an arrow function
1button.addEventListener('click', () =>2 player.handleClick()3);
Fix 3: Use an arrow function as the method
1const player = {2 name: 'John',3 score: 0,4 handleClick: () => {5 // This won't work either — arrow function in object literal6 // this is window, not player7 },8};
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:
1class Counter extends React.Component {2 constructor(props) {3 super(props);4 this.state = { count: 0 };5 }67 handleClick() {8 // this is undefined here!9 this.setState({ count: this.state.count + 1 });10 }1112 render() {13 return (14 <button onClick={this.handleClick}>15 {this.state.count}16 </button>17 );18 }19}
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
1constructor(props) {2 super(props);3 this.handleClick = this.handleClick.bind(this);4}
Fix 2: Use arrow function class property
1handleClick = () => {2 this.setState({ count: this.state.count + 1 });3};
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.
1function Counter() {2 const [count, setCount] = useState(0);34 const handleClick = () => {5 setCount(count + 1);6 };78 return <button onClick={handleClick}>{count}</button>;9}
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.