Why does AI sometimes generate arrow functions where `this` binding matters?

The item shows a candidate an AI-generated class definition where the assistant has replaced a method declaration with an arrow-function class field, breaking the inheritance contract that the surrounding subclass relies on. The candidate is asked to identify why the arrow conversion is wrong here, and when arrow functions for class methods are correct. The question probes a recurring category of AI-generated mistake: arrow functions look modern and AI assistants over-prefer them, but they have a different this-binding semantics that matters in specific class and event-handler contexts.

What this question tests

The concept under test is the difference between traditional function expressions, method shorthand, and arrow functions with respect to this binding, and how AI assistants sometimes pick the wrong shape for a given context. The ECMAScript specification defines arrow functions as not having their own this binding — they capture the lexical this from the enclosing scope. Method shorthand inside a class or object literal does have its own this, bound by the call site. AI-generated code conflates the two when the prompt is “refactor to arrow functions” or “modernize this class,” and the result is sometimes a subtle inheritance bug.

The question targets candidates who understand that “modernization” is not always a behavior-preserving refactor. An arrow function as a class field is a common ergonomic choice for event handlers (because the arrow captures this from the constructor and survives being passed to addEventListener), but it changes the prototype shape: the field lives on the instance, not the prototype, so subclasses that try to call super.method() find no method to call. Reviewing AI-generated class code for this anti-pattern is part of the senior-level review loop.

Why this is the right answer

The correct answer distinguishes the cases where each shape is appropriate. Arrow functions as instance fields are right for event handlers and callbacks where this capture matters and inheritance does not:

// Arrow as class field: right for event handlers
class TodoList extends Component {
  handleClick = (event) => {
    // `this` is the TodoList instance regardless of caller
    this.setState({ clicked: true });
  };

  render() {
    return <button onClick={this.handleClick}>Add</button>;
  }
}

Method shorthand is right for methods that are part of a class’s public API and may be overridden or called via super:

// Method shorthand: right for the class API
class TodoList {
  add(item) {
    this.items.push(item);
  }
}

class PriorityTodoList extends TodoList {
  add(item) {
    if (item.priority === 'high') this.items.unshift(item);
    else super.add(item);  // works because `add` is on the prototype
  }
}

The AI-generated bug is converting add to an arrow class field. The conversion looks identical to a casual reader, but super.add() from the subclass throws TypeError: super.add is not a function because the field on the parent instance is shadowed by the field on the child instance, and neither lives on the prototype where super looks.

A smaller version of the same bug shows up when AI assistants convert the body of forEach or map callbacks into arrow functions inside a method that uses function:

// Correct: arrow captures `this` from the surrounding method
class Cart {
  total() {
    return this.items.reduce((sum, item) => sum + this.tax(item.price), 0);
  }
}

// Buggy: function expression has its own `this` (undefined in strict mode)
class Cart {
  total() {
    return this.items.reduce(function (sum, item) {
      return sum + this.tax(item.price);  // TypeError: this is undefined
    }, 0);
  }
}

In this second case the arrow is correct and the function expression is wrong. The senior-level skill is applying the right shape per context, not picking one shape for all cases.

What the wrong answers reveal

The plausible wrong options each map onto a different misconception about this:

  • “Arrow functions are always safer, so the AI is right.” This conflates the two cases above. Arrow functions are safer for callbacks where this capture matters; they are wrong for class methods that participate in inheritance. Picking this option suggests the candidate has not internalized the prototype-vs-instance distinction.
  • “Add bind(this) in the constructor.” This is a pre-class-fields workaround that adds noise and doesn’t solve the inheritance problem. Binding a method in the constructor still puts the method on the instance, so super.method() from a subclass still fails. Picking this option suggests the candidate learned a 2015-era pattern and hasn’t updated.
  • “Use a regular function and call it via Function.call.” This is technically possible but gratuitous. The language-level fix is to use method shorthand for methods and arrow class fields for handlers. Reaching for .call to fix an AI-generated bug is a code smell.

How the sample test scores you

In the AIEH 5-question AI-Augmented JavaScript sample, this item contributes one of five datapoints aggregated into a single ai_js_proficiency score via the W3.2 normalize-by-count threshold. Binary scoring per item: 5 for the correct option, 1 for any of the three wrong options. With 5 binary items, the average ranges 1–5 and the level threshold maps avg ≤ 2 to low, ≤ 4 to mid, > 4 to high.

Data Notice: Sample-test results are directional indicators only. A 5-question sample can’t reliably distinguish between “understands this binding deeply” and “got lucky on these specific items”; for a verified Skills Passport credential, take the full 50-question assessment.

The full assessment probes class semantics, prototypes, event-handler ergonomics, strict mode, and the specific gotchas (bind chains, new.target, super in static methods) at depth. See the scoring methodology for how AI-Augmented JavaScript scores map onto the AIEH 300–850 Skills Passport scale.

  • Class fields proposal and timing. Arrow class fields shipped in stable Node.js and major browsers around 2022; AI training data from before that period sometimes generates pre-fields workarounds (constructor binding, decorator patterns) that are no longer needed. Reviewers should upgrade these when they appear.
  • React useCallback and stable references. In function components, the equivalent of “method on instance vs method on prototype” is “callback wrapped in useCallback vs inline arrow.” AI-generated React code sometimes uses inline arrows in JSX where stable references matter for child memoization; the review skill transfers.
  • bind and partial application. Function.prototype.bind remains useful for partial application (binding leading arguments) and for explicit-this contexts; the AI-augmented reviewer’s job is recognizing when bind is the right tool and when it is cargo-culted.

For the broader AI-Augmented JavaScript lineup including the full 50-question assessment, see the tests catalog and javascript fundamentals prep for related study materials. Hiring teams should explore the assess page for ready-to-deploy skill assessments.


Sources

Try the question yourself

This explainer covers what the item measures. To see how you score on the full ai augmented javascript family, take the free 5-question sample.

Take the ai augmented javascript sample