DEV Community

Cover image for Building a Chain Calculator in JavaScript: Method Chaining for Clean Arithmetic
Mohammad Talim
Mohammad Talim

Posted on

Building a Chain Calculator in JavaScript: Method Chaining for Clean Arithmetic

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
Enter fullscreen mode Exit fullscreen mode

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;
  }
}
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

3. Division with Error Handling

divide(value) {
  if (value === 0) {
    throw new Error("Division by zero is not allowed");
  }
  this.result /= value;
  return this;
}
Enter fullscreen mode Exit fullscreen mode

4. Exponentiation

power(value) {
  this.result **= value;
  return this;
}
Enter fullscreen mode Exit fullscreen mode

5. Retrieving the Result

getResult() {
  return this.result;
}
Enter fullscreen mode Exit fullscreen mode

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;
  }
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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.

Further Reading

Top comments (0)