Schema Editor
jQuery $(this) Inside Arrow Functions Fails Silently After a Module Split
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 Binding | this Scope | $(this).data() Output After Module Split | Fix |
|---|---|---|---|
Arrow Function (() =>) | Lexical Outer Scope | undefined (Silent Failure) | Replace with function() or e.currentTarget |
Standard (function()) | Clicked DOM Element | Correct Attribute Value | Production Standard |
$(e.currentTarget) | Clicked DOM Element | Correct 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 →