[Easy] LeetCode JS 30 - 2665. Counter II
March 5, 2024
LeetCode 30 Days of JavaScript
This question is from LeetCode's 30 Days of JavaScript Challenge
2665. Counter IIQuestion 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
Looking to practice more questions like these? We recommend GreatFrontEnd, the best platform for honing your frontend interview skills!
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.
getsimply returns the current value ofvalue.incrementincreasesvalueby 1 and returns the updated value.decrementdecreasesvalueby 1 and returns the updated value.resetsetsvalueback 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 
constructorfunction is used to initialize a newCounterobject. - It takes an optional 
initialValueargument, which defaults to 0. - Inside the constructor, the 
this.initialValueandthis.valueproperties are set using theinitialValueargument. - The 
thiskeyword here refers to the newly created counter object instance. It's used to assign the initial value to the object's properties. 
Methods:
- The 
getmethod returns the current value of the counter. - The 
incrementmethod increments the counter's value by 1 and returns the new value. - The 
decrementmethod decrements the counter's value by 1 and returns the new value. - The 
resetmethod resets the counter's value to its initial value and returns the new value. - In all of these methods, the 
thiskeyword refers to the current counter object instance. It's used to access and modify the object's properties (this.valueandthis.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);
}