JavaScript Arrow Functions
JavaScript Arrow Functions Interview with follow-up questions
1. What is an arrow function in JavaScript?
An arrow function is a compact syntax for function expressions, introduced in ES2015 (ES6). Beyond brevity, it differs from regular functions in a few semantic ways that interviewers care about more than the shorthand.
const add = (a, b) => a + b; // implicit return
const square = n => n * n; // single param, no parens needed
const greet = () => ({ ok: true }); // wrap object literal in parens
What makes arrows distinct (not just shorter):
- No own
this— they close overthisfrom the enclosing lexical scope. Great for callbacks; bad as object/prototype methods that need dynamicthis. - No own
arguments— use rest params(...args)instead. - Can't be used with
new— they have no[[Construct]]and noprototype. - No own
superornew.target.
So the right framing is: arrows are the default for inline callbacks (map, setTimeout, Promise handlers) precisely because they inherit this, and you fall back to regular functions/method shorthand when you need a dynamic this.
Follow-up 1
How does it differ from a regular function?
Arrow functions differ from regular functions in a few ways:
- Syntax: Arrow functions have a shorter syntax compared to regular functions.
- Binding of 'this': Arrow functions do not bind their own 'this' value, instead, they inherit the 'this' value from the enclosing lexical scope.
- No 'arguments' object: Arrow functions do not have their own 'arguments' object, so you cannot access the arguments passed to the function using 'arguments' keyword.
Follow-up 2
Can you provide an example of an arrow function?
Sure! Here's an example of an arrow function that adds two numbers:
const add = (a, b) => a + b;
console.log(add(2, 3)); // Output: 5
In this example, the arrow function add takes two parameters a and b and returns their sum.
Follow-up 3
What are the benefits of using arrow functions?
There are several benefits of using arrow functions:
- Concise syntax: Arrow functions have a shorter and more concise syntax compared to regular functions, making the code easier to read and write.
- Lexical 'this' binding: Arrow functions do not bind their own 'this' value, which means they inherit the 'this' value from the surrounding scope. This can help avoid confusion and simplify the code.
- No 'arguments' object: Arrow functions do not have their own 'arguments' object, which can lead to cleaner and more predictable code.
- Implicit return: If the arrow function has a single expression, it will be implicitly returned without the need for the
returnkeyword.
Follow-up 4
In what scenarios would you use an arrow function?
Arrow functions are commonly used in the following scenarios:
- Callback functions: Arrow functions are often used as callback functions, especially in scenarios where the 'this' value needs to be preserved.
- Iteration methods: Arrow functions are frequently used with iteration methods like
map,filter, andreduceto provide concise and readable code. - Event handlers: Arrow functions are useful for defining event handlers, as they automatically inherit the 'this' value from the surrounding scope.
- Shorter function expressions: Arrow functions can be used to write shorter and more concise function expressions in general.
2. How does 'this' behave in arrow functions?
Arrow functions have no own this. Instead, this is resolved lexically — it's whatever this is in the scope where the arrow was defined, and it never changes based on how the arrow is called. This is the single most-tested fact about arrows.
class Timer {
seconds = 0;
start() {
setInterval(() => {
this.seconds++; // `this` = the Timer instance (lexical)
}, 1000);
}
}
A regular function callback here would lose this (it'd be undefined or the global object), which is exactly the bug arrows solve.
Consequences interviewers probe:
call/apply/bindcan't change an arrow'sthis— thethisargument is ignored.- Don't use arrows as object methods when you need
thisto be the object:
const obj = {
name: 'x',
bad: () => this.name, // `this` is NOT obj (lexical, outer scope)
good() { return this.name; }, // method shorthand — `this` is obj
};
- Same reason they're poor for prototype methods and DOM handlers that need the element via
this.
Follow-up 1
How is it different from 'this' in regular functions?
In regular functions, the value of 'this' is determined by how the function is called. It can vary depending on the context in which the function is invoked.
Follow-up 2
Can you provide an example where 'this' behaves differently in arrow functions and regular functions?
Sure! Here's an example:
const obj = {
name: 'John',
regularFunc: function() {
console.log(this.name);
},
arrowFunc: () => {
console.log(this.name);
}
};
obj.regularFunc(); // Output: 'John'
obj.arrowFunc(); // Output: undefined
In this example, the 'regularFunc' is a regular function and 'arrowFunc' is an arrow function. When 'regularFunc' is called, 'this' refers to the 'obj' object, so it outputs 'John'. However, when 'arrowFunc' is called, 'this' refers to the enclosing scope (which is the global scope in this case), so it outputs 'undefined'.
Follow-up 3
What are the implications of this difference in behavior?
The difference in behavior of 'this' in arrow functions and regular functions can have implications when it comes to object methods, event handlers, and callback functions. Arrow functions are useful when you want to preserve the value of 'this' from the surrounding context, while regular functions allow 'this' to be dynamically determined based on how the function is called.
3. Can arrow functions be used as constructors?
No — arrow functions cannot be used as constructors. Calling one with new throws a TypeError.
const Person = (name) => { this.name = name; };
const p = new Person('Ada'); // TypeError: Person is not a constructor
Why, and what an interviewer wants you to explain:
- Arrow functions have no internal
[[Construct]]method, sonewhas nothing to invoke. - They have no
prototypeproperty, so there's no object for a new instance to inherit from. - They have no own
this—newworks by binding a freshthis, but an arrow'sthisis fixed lexically and can't be rebound. - They also lack their own
arguments,super, andnew.target.
When you need a constructor, use a class (the modern choice) or a regular function:
class Person {
constructor(name) { this.name = name; }
}
Follow-up 1
Why or why not?
Arrow functions do not have their own 'this' value. They inherit the 'this' value from the enclosing lexical scope. This means that the 'this' value inside an arrow function is the same as the 'this' value outside the arrow function. Constructors, on the other hand, require the use of the 'new' keyword to create a new instance of an object and set the 'this' value to the newly created object. Since arrow functions do not have their own 'this' value, they cannot be used as constructors.
Follow-up 2
What happens if you try to use an arrow function as a constructor?
If you try to use an arrow function as a constructor by calling it with the 'new' keyword, a TypeError will be thrown. This is because arrow functions do not have a prototype property, which is necessary for creating new instances of objects.
Follow-up 3
Can you provide an example?
Sure! Here's an example that demonstrates the use of an arrow function as a constructor:
const Person = (name) => {
this.name = name;
};
const person = new Person('John'); // Throws a TypeError
In this example, the arrow function 'Person' is intended to be used as a constructor for creating instances of a 'Person' object. However, when we try to create a new instance of 'Person' using the 'new' keyword, a TypeError is thrown because arrow functions cannot be used as constructors.
4. Can you explain the concept of lexical scoping in the context of arrow functions?
Lexical scoping means a variable's scope is determined by where it's written in the source, not by where or how it's called. Inner functions can reach variables of the enclosing scopes, resolved at definition time.
Arrow functions follow normal lexical scoping for variables — but the notable thing is that they also resolve this, arguments, super, and new.target lexically, since they have none of their own. A regular function gets a fresh this/arguments per call; an arrow simply borrows them from the surrounding scope.
function group(items) {
const tag = 'item';
return items.map(x => `${tag}:${x}`); // arrow closes over `tag` lexically
}
And the this consequence — the part interviewers are really testing:
const obj = {
values: [1, 2, 3],
factor: 10,
scale() {
// arrow inherits `this` from scale(), so this.factor works
return this.values.map(v => v * this.factor);
},
};
obj.scale(); // [10, 20, 30]
So lexical scoping is why arrows are ideal as callbacks: they "see" the variables and the this of the place they were written, with no this-rebinding surprises.
Follow-up 1
How does it differ from dynamic scoping?
Dynamic scoping is a different scoping mechanism where the scope of a variable is determined by the current execution context, rather than the location in the source code. In dynamic scoping, the variables used inside a function are resolved in the scope where the function is called, rather than where it is defined. This can lead to unexpected behavior and makes the code harder to reason about.
Follow-up 2
Can you provide an example of lexical scoping with an arrow function?
Sure! Here's an example:
const outerFunction = () => {
const message = 'Hello';
const innerFunction = () => {
console.log(message);
};
innerFunction();
};
outerFunction();
In this example, the innerFunction is an arrow function that is defined inside the outerFunction. It has access to the message variable from its surrounding scope, which is the outerFunction. When innerFunction is called, it will log 'Hello' to the console.
Follow-up 3
What are the benefits of lexical scoping?
Lexical scoping offers several benefits:
- Simpler code: Lexical scoping allows for cleaner and more readable code by reducing the need for global variables and explicit parameter passing.
- Closures: Lexical scoping enables the creation of closures, which are functions that have access to variables from their surrounding scope even after the outer function has finished executing.
- Code reusability: Lexical scoping allows functions to access variables from their surrounding scope, making it easier to reuse and compose functions.
- Improved performance: Lexical scoping can improve performance by reducing the need for variable lookups in higher scopes.
5. How do you handle methods that require their own 'this' value in an object when using arrow functions?
Because an arrow function takes this lexically from its surrounding scope, it's the wrong choice for an object method that needs this to be the object itself. The fix is to use a method that has its own dynamic this — method shorthand or a regular function:
const obj = {
name: 'Widget',
// BAD: arrow's `this` is the outer scope, not `obj`
badGreet: () => `Hi from ${this?.name}`, // undefined
// GOOD: method shorthand has its own `this`
greet() { return `Hi from ${this.name}`; },
};
obj.greet(); // "Hi from Widget"
Related points interviewers expect:
- Mixing the two on purpose: a regular method can contain an arrow so the inner callback inherits the method's
this— the common pattern formap/setTimeout/event callbacks inside a method. bind,call,applysetthisfor regular functions but are ignored by arrows.- For class methods, declare them normally; if you need an auto-bound handler (e.g. passing a method as a callback), use a class field with an arrow so
thisstays the instance:
class Button {
label = 'OK';
onClick = () => console.log(this.label); // bound to instance
}
Follow-up 1
Can you provide an example?
Sure! Here's an example that demonstrates the issue with using arrow functions as methods in objects:
const obj = {
name: 'John',
sayHello: () => {
console.log('Hello, ' + this.name);
}
};
obj.sayHello(); // Output: Hello, undefined
In this example, the arrow function sayHello is defined within the obj object. However, when sayHello is called, the 'this' value inside the arrow function does not refer to the obj object, resulting in undefined.
Follow-up 2
What are the alternatives to handle this scenario?
There are a few alternatives to handle the scenario of methods requiring their own 'this' value in an object when using arrow functions:
Use regular function expressions: Instead of using arrow functions, you can define the methods as regular function expressions. This way, each method will have its own 'this' value that refers to the object itself.
Use bind(): You can use the
bind()method to bind the 'this' value of the arrow function to the object. This creates a new function with the specified 'this' value.Use class methods: If you are working with classes, you can define the methods as class methods using the
methodsyntax. Class methods automatically bind the 'this' value to the object instance.
Follow-up 3
What are the implications of using arrow functions in this scenario?
When using arrow functions as methods in objects, the 'this' value will not refer to the object itself. Instead, it will be determined by the surrounding context where the arrow function is defined. This can lead to unexpected behavior and bugs if the arrow function relies on the 'this' value being the object. It is important to be aware of this behavior and choose the appropriate function type (arrow function or regular function expression) based on the desired 'this' binding.
Live mock interview
Mock interview: JavaScript Arrow Functions
- Read your scene and goals
- Talk it out; goals tick off live
- Get a score and stronger lines
Your voice and your AI key never touch our servers; the key stays in this browser and is sent only to Google. Only your round scores are saved to track progress.