Are there advantages to using closures to maintain state rather than class?

Asked

Viewed 101 times

3

It is very common to use classes to encapsulate state and some methods that modify it, such as this counter:

class Counter {
  #val = 0;
  
  increment(step = 1) {
    this.#val += step;
  }
  
  retrieve() {
    return this.#val;
  }
}

const counter = new Counter();
counter.increment();
counter.increment();
console.log(counter.retrieve()); // 2

But another way to do the same thing is to keep the state in a closure, which still encapsulates the state:

function createCounter() {
  let val = 0;
  
  return {
    increment: (step = 1) => val += 1,
    retrieve: () => val
  };
}

const counter = createCounter();
counter.increment();
counter.increment();
console.log(counter.retrieve()); // 2

Of course it is the preference of each person to use one or the other, but I would like to know if the second method has any advantage over the first - which is undoubtedly more popular.

  • 2

    Not generally, but JS has some idiosyncrasies that might bring some advantage, so I’ll wait for some with friendly authority on the subject to answer. In any normal code, of normal people, in normal language, you can always do it in a simpler way. I think gambiarra, but some language may require a.

1 answer

2


This article How to decide between classes v. closures in Javascript explains from a direct and with examples, the differences between closures and class in JS, but I will put here a summary of what I found more interesting to take into account.

  • closure and class has different fundamental behaviors, where the closure supports encapsulation, being encapsulation one of the main concepts of OOP, on the other hand classes in JS do not support it. This difference has to be taken into account for verses prior to ES2019 where it has a proposal to use var and private methods with the use of the #, as in your example. This feature is implemented in babel and it’s not all browsers that support this feature. Without this var private feature, nothing would stop me from doing:
class Counter {
        val = 0;

        increment(step = 1) {
          this.val += step;
        }

        retrieve() {
          return this.val;
        }
      }

      const counter = new Counter();
      counter.val = 100; // alterar diretamente o valor de val porque não possui encapsulamento.
      console.log(counter.retrieve()); // 2
  • We can manipulate the private data of the class implementation, making the class implementation more fragile (for versions prior to ES2019).
  • class need the new to create an instance, while closure just call the function.
  • Each instance of the class shares the same prototype, meaning that a change in the prototype will also affect all instances (example below). Meanwhile, all instances created by closure are unique.
class Counter {
        val = 0;

        increment(step = 1) {
          this.val += step;
        }

        retrieve() {
          return this.val;
        }
      }

      const counter = new Counter();
      const counter1 = new Counter();

      Counter.prototype.retrieve = () => 'Hello there!'

      console.log(counter1.retrieve()); // Hello there 
      console.log(counter.retrieve()); // Hello there 

  • And finally, classes are more efficient in terms of performance than closure, because the class creates a reference in memory where all the instances created will share from this reference, that is, it stores in memory something in common that will be used by many. Already closures create instances separate from each other, ie, each instance of a closure will create a unique reference in memory, which will obviously consume more system memory. In short, if there is no need to create multiple instances of an object, closures will be a good option. Otherwise, classes will be more performatic, but should pay attention to the care for versions of ES that do not support encapsulation.

As you said in your question, it is up to each person to decide what to use. At first I came to think that classes were syntactic sugar for closures, but over time, I realized that’s not quite so. I particularly prefer closure because I feel more comfortable with a more functional paradigm in JS, but I don’t ignore which classes have their merit although the implementation in JS is still a little weird. Anyway, I hope I’ve helped your doubt and it’s up to the discussion.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.