[Easy] LeetCode JS 30 - 2665. Counter II

March 5, 2024

☕️ Support Us
Your support will help us to continue to provide quality content.👉 Buy Me a Coffee

LeetCode 30 Days of JavaScript

This question is from LeetCode's 30 Days of JavaScript Challenge

2665. Counter II

Question Prompt

Imagine you're working on a project that requires tracking various metrics. We need a flexible way to manage counters within our code. Your task is to design a function called createCounter that can be used to generate custom counters with specific starting values.

createCounter will return an object with the following method

  • get(): Returns the current value of the counter.
  • increment(): Increments the counter by 1 and returns the updated value.
  • decrement(): Decrements the counter by 1 and returns the updated value.
  • reset(): Resets the counter back to its initial value.
const counter = createCounter(4);
counter.get(); // 4
counter.increment(); // 5
counter.increment(); // 6
counter.get(); // 6
counter.reset(); // 4
counter.decrement(); // 3

Solutions

The createCounter function creates a counter object with methods for getting, incrementing, decrementing, and resetting its value. The key to its functionality lies in how it utilizes closures.

Firstly, the function defines a variable value with the optional initialValue argument. This variable holds the current counter value and is kept private within the function scope.

Then, it defines four inner functions: get, increment, decrement, and reset. These functions form the closure. Each function can access the private value variable due to JavaScript's lexical scoping rules. Even though the outer createCounter function may have already returned, the inner functions still retain access to its variables due to the closure.

  • get simply returns the current value of value.
  • increment increases value by 1 and returns the updated value.
  • decrement decreases value by 1 and returns the updated value.
  • reset sets value back to its initial value and returns it.

Finally, the createCounter function returns an object containing only the inner functions (get, increment, decrement, and reset) as properties. This returned object acts as the counter interface, exposing the necessary methods while keeping the internal value private and protected from outside modifications.

In essence, the closure ensures that the inner functions always have access to the current counter value, even after the outer function has finished executing. This is crucial for maintaining the counter's state and allowing users to manipulate it through the exposed methods

function createCounter(initialValue = 0) {
  let value = initialValue;

  function get() {
    return value;
  }

  function increment() {
    value += 1;
    return value;
  }

  function decrement() {
    value -= 1;
    return value;
  }

  function reset() {
    value = initialValue;
    return value;
  }

  return {
    get,
    increment,
    decrement,
    reset,
  };
}

Or we can rewrite using class . The key here is the this keyword in JavaScript. In JavaScript, the this keyword refers to the current object context. Its value depends on how the function is called or the object is used.

In the Counter class, the this keyword inside the constructor, methods, and createCounter function refers to the counter object instance being created or used. This allows you to access and modify the object's properties (this.value and this.initialValue) within these methods.

Constructor:

  • The constructor function is used to initialize a new Counter object.
  • It takes an optional initialValue argument, which defaults to 0.
  • Inside the constructor, the this.initialValue and this.value properties are set using the initialValue argument.
  • The this keyword here refers to the newly created counter object instance. It's used to assign the initial value to the object's properties.

Methods:

  • The get method returns the current value of the counter.
  • The increment method increments the counter's value by 1 and returns the new value.
  • The decrement method decrements the counter's value by 1 and returns the new value.
  • The reset method resets the counter's value to its initial value and returns the new value.
  • In all of these methods, the this keyword refers to the current counter object instance. It's used to access and modify the object's properties (this.value and this.initialValue).

Then, for createCounter , takes an optional initialValue argument and returns a new Counter object initialized with that value. Inside the function, the new Counter(initialValue) expression creates a new instance of the Counter class using the initialValue argument.

Noted that the this keyword inside the Counter class constructor refers to the newly created counter object, not the createCounter function itself. So we directly return the new instance.

class Counter {
  constructor(initialValue = 0) {
    this.initialValue = initialValue;
    this.value = initialValue;
  }
  get() {
    return this.value;
  }
  increment() {
    this.value += 1;
    return this.value;
  }
  decrement() {
    this.value -= 1;
    return this.value;
  }
  reset() {
    this.value = this.initialValue;
    return this.value;
  }
}

function makeCounter(initialValue = 0) {
  return new Counter(initialValue);
}
☕️ Support Us
Your support will help us to continue to provide quality content.👉 Buy Me a Coffee