Engineering Journal
Schema Editor
Schema Editor

jQuery $(this) Inside Arrow Functions Fails Silently After a Module Split

2026-06-04

TLDR

Using jQuery $(this) inside arrow function event handlers ($(el).on('click', () => ... )) works inside single-file scripts by coincidence: the outer lexical this happens to point to a global scope containing matching properties. When refactoring the script into ES modules, arrow functions retain lexical scope (this becomes the imported module object), causing $(this).data(...) to silently return undefined. Replacing arrow functions with standard function() declarations or using $(e.currentTarget) fixes the bug.
Event Handler Bindingthis Scope$(this).data() Output After Module SplitFix
Arrow Function (() =>)Lexical Outer Scopeundefined (Silent Failure)Replace with function() or e.currentTarget
Standard (function())Clicked DOM ElementCorrect Attribute ValueProduction Standard
$(e.currentTarget)Clicked DOM ElementCorrect Attribute Value (Works in both)Recommended Practice

Problem statement: the silent toolbar button failure

During a modular refactor of a canvas application, a toolbar button stopped working.

Clicking the button triggered the click event, but the expected mode switch failed to execute. Adding console.log($(this).data('mode')) printed undefined, even though the HTML element contained data-mode="trace".


Technical failure mode: lexical scope vs. Dynamic event binding

Arrow functions in JavaScript do not bind their own this context; they inherit this from surrounding lexical scope.

// DEFECTIVE IMPLEMENTATION: Arrow function inherits module 'this'
$('#traceBtn').on('click', () => {
  const mode = $(this).data('mode'); // DEFECT: $(this) refers to the imported module!
  setMode(mode);
});

In the original single-file script, the outer this pointed to a global module object that happened to contain a mode property, making the call work by coincidence. Once split into ES modules, this pointed to the module object instance, which lacked jQuery .data() attributes.


The fix: standard functions or e.currentTarget

Option 1: standard function() declarations

Convert event handlers needing element this context to standard function syntax:
// REFACTORED: Standard function binds 'this' to clicked DOM element
$('#traceBtn').on('click', function() {
  const mode = $(this).data('mode'); // Correct: 'this' points to #traceBtn
  setMode(mode);
});

Option 2: universal e.currentTarget (recommended)

Use e.currentTarget to extract element references safely inside arrow functions:
// REFACTORED: e.currentTarget works identically in both arrow and standard functions
$('#traceBtn').on('click', (e) => {
  const mode = $(e.currentTarget).data('mode'); // Always points to clicked DOM element!
  setMode(mode);
});
Rule of thumb: Avoid using $(this) inside arrow function event handlers. Use $(e.currentTarget) to access event target elements reliably across modular ES imports.
Read this post in the full Engineering Journal →