In this post, we'll explore how to design a Chain Calculator—a calculator class that lets you perform a series of arithmetic operations using a fluent, chainable interface. This is a popular interview question and a great exercise to deepen your understanding of JavaScript classes and method chaining.
Why Method Chaining?
Method chaining is a programming pattern that allows multiple method calls in a single statement, improving code readability and succinctness. It's used widely in libraries like jQuery and Lodash, and it's a great tool for creating intuitive APIs. By building a chainable calculator, you'll learn how to design methods that return this
, enabling seamless chaining of operations.
The Problem
Design a Chain Calculator in JavaScript that supports method chaining for basic arithmetic operations:
- Addition
- Subtraction
- Multiplication
- Division
- Exponentiation (power)
The calculator should allow users to perform a sequence of operations in one line, like this:
const calc = new Calculator(10);
const result = calc.add(5).subtract(3).multiply(2).divide(3).getResult(); // 8
Requirements
- Initial value: The calculator starts with a number passed to its constructor.
-
Chainable methods: Support these methods:
add(number)
subtract(number)
multiply(number)
divide(number)
power(number)
- All arguments are valid numbers.
- Division by zero should throw an error.
- The final result is retrieved with
getResult()
.
Approach: Using Classes and Chaining
To achieve method chaining, each arithmetic method will:
- Modify the calculator's internal state.
- Return
this
so calls can be chained.
We'll use a class to encapsulate state and behavior. For error handling, division by zero will throw an exception.
Why Not a Functional Approach?
You might wonder: why not just use functions and closures? While possible, the class-based approach is more idiomatic for method chaining in JavaScript and is more readable, especially in interview settings.
Implementation: Step by Step
Let's build the Calculator
class step by step.
1. The Skeleton
class Calculator {
constructor(value) {
this.result = value;
}
}
2. Arithmetic Methods
Each method updates the result and returns this
:
add(value) {
this.result += value;
return this;
}
subtract(value) {
this.result -= value;
return this;
}
multiply(value) {
this.result *= value;
return this;
}
3. Division with Error Handling
divide(value) {
if (value === 0) {
throw new Error("Division by zero is not allowed");
}
this.result /= value;
return this;
}
4. Exponentiation
power(value) {
this.result **= value;
return this;
}
5. Retrieving the Result
getResult() {
return this.result;
}
6. The Complete Class
class Calculator {
constructor(value) {
this.result = value;
}
add(value) {
this.result += value;
return this;
}
subtract(value) {
this.result -= value;
return this;
}
multiply(value) {
this.result *= value;
return this;
}
divide(value) {
if (value === 0) {
throw new Error("Division by zero is not allowed");
}
this.result /= value;
return this;
}
power(value) {
this.result **= value;
return this;
}
getResult() {
return this.result;
}
}
Example Usage
Let's see this calculator in action:
const calc = new Calculator(10);
console.log(calc.add(5).subtract(3).multiply(2).divide(3).getResult()); // Output: 8
More Examples
Expression | Output | Explanation |
---|---|---|
new Calculator(10).add(5).subtract(3).getResult() |
12 | 10 + 5 - 3 = 12 |
new Calculator(2).multiply(5).power(2).getResult() |
100 | (2 × 5)² = 10² = 100 |
new Calculator(20).divide(4).add(2).multiply(3).getResult() |
21 | 20 ÷ 4 = 5, 5 + 2 = 7, 7 × 3 = 21 |
new Calculator(5).divide(0).getResult() |
Error | Throws error for division by zero |
new Calculator(7).getResult() |
7 | No operations; returns initial value |
Time and Space Complexity
- Time Complexity: O(1) per operation (each method does a simple calculation).
- Space Complexity: O(1) (stores only a single number).
Key Takeaways
- Always return
this
from methods to enable chaining. - Handle errors (like division by zero) gracefully.
- This pattern—called the fluent interface—makes APIs easy and intuitive to use.
Top comments (0)