HuntExams Academy logo
JavaScriptIntermediate#functions#es6

Difference between arrow functions and regular functions?

Answer

Arrow functions have no own this, arguments, new.target or prototype, cannot be used with new, and cannot be generators. They are ideal for callbacks and bad for object methods or constructors.

Example

const obj = { v: 1, get(){ return [1].map(() => this.v); } };
obj.get(); // [1] — arrow keeps outer this
new (() => {})(); // TypeError

Detailed explanation

Arrow functions differ from regular functions mainly in how they handle execution context, not just in their shorter syntax. An arrow captures `this` lexically from its enclosing scope; calling it through an object does not give it that object as `this`. A regular function has its own `this` binding, generally determined by how it is called. For example, `obj.method()` supplies `obj` as the receiver for a regular method. This distinction matters when callbacks need access to the surrounding method’s receiver.

In `const obj = { v: 1, get() { return [1].map(() => this.v); } };`, calling `obj.get()` returns `[1]`. The regular `get` method receives `obj` as `this`, and the arrow callback captures that binding. Replacing the callback with a regular function would not automatically preserve the method’s `this`; you would need an explicit mechanism such as the second argument to `map` or `bind`. Conversely, defining `get` itself as an arrow would capture the enclosing scope’s `this`, not `obj`. An object literal does not create a new `this` scope.

Arrows also have no own `arguments` object or `new.target` binding. References to these resolve through the enclosing lexical environment where available; rest parameters such as `(...args)` are usually clearer for collecting an arrow’s arguments. Arrows cannot be constructors: `new (() => {})()` throws a `TypeError`. They have no own `prototype` property by default, although they still inherit from `Function.prototype`. They cannot be generator functions either. Ordinary function declarations and expressions can be constructors, but not every non-arrow function is constructible: concise object methods and generator functions are important exceptions.

Arrows support implicit returns for expression bodies; block bodies require an explicit `return`. Returning an object literal implicitly requires parentheses, as in `() => ({ v: 1 })`. Interviewers expect you to connect these rules to practical choices: use arrows for callbacks that should retain outer `this`, and regular methods when the receiver should determine `this`. Also remember that `call`, `apply`, and `bind` cannot replace an arrow’s captured `this`, although they can still supply arguments.

Key points to remember

  • Arrows capture lexical `this`; regular functions generally receive `this` according to their invocation.
  • Arrows have no own `arguments` or `new.target`; use rest parameters for their argument collection.
  • Arrows cannot be called with `new` and have no own `prototype` property by default.
  • Arrows cannot be generators and support implicit returns only with expression bodies.
  • Use arrows for callbacks needing outer `this`, and regular methods for receiver-dependent behaviour.

Common mistakes candidates make

  • Assuming an arrow stored as an object property receives that object as `this`.
  • Expecting `call`, `apply`, or `bind` to change an arrow’s captured `this`.
  • Claiming every regular function is constructible or confusing an arrow’s missing own `prototype` with having no prototype chain.

Likely follow-up questions

Can bind change an arrow function’s this?

No, an arrow resolves `this` through its enclosing lexical scope. `bind` can still create a wrapper that pre-fills arguments, but its `thisArg` cannot override the arrow’s `this`.

What happens when a regular method is detached from its object?

With `const get = obj.get; get();`, the invocation no longer supplies `obj` as the receiver. In strict mode, `this` inside the method is `undefined`, so accessing `this.v` throws; binding the method to `obj` preserves the receiver.

Are arrow functions always unsuitable as class methods?

No: a class field such as `handleClick = () => this.save()` captures the instance’s `this`, which is useful when passing it as a callback. The trade-off is a separate function per instance rather than one shared prototype method.

Interview tip: Start with lexical versus call-dependent `this`, trace the supplied callback example, and then summarise the constructor, arguments, and generator restrictions.

Related Interview Questions

1
JavaScriptIntermediate#prototypes#oop

What is prototypal inheritance?

Open
2
JavaScriptIntermediate#oop#es6

What is the difference between an ES6 class and a constructor function?

Open
3
JavaScriptAdvanced#event-loop#async

Explain the event loop.

Open