1

For closures which main goal it's to create another functions, I was wondering if in modern javascript, it's better to just use classes in modern javascript.

// Closure way private counter
const countPlusOne = () => {
    let count = 0;
    return () =>{
        count++;
        console.log(count);
    }
}
let demoAdd = countPlusOne();
demoAdd(); // 1
demoAdd(); // 2
demoAdd(); // 3

To be honest, I never liked the use of closures in that way (but I think they're great for things like middlewares) as are hard to read.

So, should I refactor closures like the one up, to classes? Their behavior seem more analogous to typical Objects from other languages.

// Class way private counter
class countPlusClass{
    count = 0;
    add(){
        this.count++;
        console.log(this.count)
    }
}
const demo = new countPlusClass();
demo.add(); // 1
demo.add(); // 2
demo.add(); // 3

Javier Garcia
  • 33
  • 1
  • 5
  • 1
    use whatever is appropriate – Bravo Mar 30 '22 at 02:25
  • 1
    Since it looks like you may be new here, the general idea is that you engage with the answers you were provided. If they don't answer your question, then you can comment on them and explain what is still missing. You can upvote answers that help you and if one answer appears to provide what you need and answer your question, you can mark it as the best answer by clicking the checkmark to the left of the answer (which also earns you some reputation points here). Stackoverflow works best when you engage with those who tried to help you, rather than post, read answers and then disappear. – jfriend00 Apr 07 '22 at 22:02
  • @jfriend00 Sorry, my mistake, thanks a lot for the guidance. I wasn't planning on being rude, I'll do better from now on. – Javier Garcia Apr 08 '22 at 05:28
  • So, did any of these responses below answer your question? – jfriend00 Apr 08 '22 at 05:39

4 Answers4

3

A closure has a significant advantage over a class the way you're imagining: with a class, if you use a public class field like you are, any code with access to the instance can modify its value. This is usually undesirable - scope should generally be constrained as possible and you don't want the correctness of your class to depend on consumers of the class not modifying it (whether accidentally or deliberately).

class countPlusClass{
    count = 0;
    add(){
        this.count++;
        console.log(this.count)
    }
}
const demo = new countPlusClass();
demo.add(); // 1
demo.add(); // 2


// some code elsewhere in the codebase that has access to the demo instance:
demo.count = 55555;


demo.add(); // not 3...

Closures, in contrast, are completely private (barring strange, exceptional circumstances).

If you were to use a class, and you wanted to emulate the privacy of closures, make sure to use private class fields instead, so they can't be modified outside the class.

class countPlusClass{
    #count = 0;
    add(){
        this.#count++;
        console.log(this.#count)
    }
}
const demo = new countPlusClass();
demo.add(); // 1
demo.add(); // 2


// some code elsewhere in the codebase that has access to the demo instance
// cannot modify the private field
demo.count = 55555;


demo.add(); // not 3...

As for which is better, a closure-based object or a class? That's up to each individual developer.

CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
  • so - it's a matter of opinion which to use in which circumstance – Bravo Mar 30 '22 at 02:33
  • You can make private fields in classes: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Private_class_fields – quilkin Apr 14 '23 at 08:18
3

No, classes aren't always better. They're just different. I'd say the main differences are

  • the interface of the thing returned by the constructor/factory function. A class instance has properties and methods, and usually multiple of them, whereas a closure is simply a function that you can call - with a single functionality. The syntax to invoke them is different, the extra method name is sometimes superfluous and sometimes beneficial.
  • In OOP, objects are expected to have an identity and a state. In FP, functions are expected to be pure. Sure, you don't need to follow a specific paradigm, and stateless objects are fine as are impure functions (though maybe call them "procedures" then), but keep these conventions in mind when arguing about readability and maintainability.

So choose wisely. Do you (possibly in the future) need multiple methods? Do you encapsulate state? Then use a class to create objects. Do you only need a function to call? Then create a closure.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • what if you just return an object (or array) of functions from the parent function? Then you can just call them like this: `demo.add(5); demo.getValue()` – Seangle Oct 12 '22 at 09:41
  • @Seangle That's called method chaining, but it works with both classes and closures, no difference there – Bergi Oct 12 '22 at 20:05
2

Classes are not always better. It really depends upon the circumstances. Each has their place in your programming toolset.

A class has the following advantages:

  1. There's defined syntax in the language
  2. You can sub-class a class to extend it
  3. You can more easily have many properties and many methods.
  4. Methods are automatically non-enumerable and run in strict mode.
  5. The syntax in the code that uses a class somewhat self-describes what is happening since new countPlusClass() makes it clear you're creating an object that will then have methods and probably state. That's not as obvious with the closure you show.
  6. For object with a lot of methods there's some space-savings benefit to the prototype that a class uses.
  7. Developer tools will recognize an instance of a class and know how to display it, auto-complete when typing code for it, how to represent it in the debugger, how to use it in error messages, etc...

A closure has these advantages:

  1. The data in the closure is complete private. Nobody can get to it from outside the closure.
  2. In some circumstances, the caller may find it takes less code to use the closure since you make one function call (sometimes passing arguments) and you get back another function that then implements the one thing this is supposed to do (your mention of middleware comes to mind).

So, I'd say that if you want or need or value any of the benefits of the class, then use the class.

If you don't want or need any of the benefits of the class and the simpler interface of the closure meets your needs or if you really need the privacy of the closure, then you can choose the closure.

I'd say that for a given circumstance, one of these tools may be a better "fit" for the problem at hand.


As has been mentioned in the comments, you can also have factory functions that may be closures (retain private state in a closure) and may return an object with methods and/or properties that can even be an object created by instantiating a class. So, these concepts can all be combined too to get some of the benefits of both.

jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • so - it's a matter of opinion which to use in which circumstance – Bravo Mar 30 '22 at 02:32
  • I think "*there's syntax for it*" and "*you can extend it*" also apply to closures. I wouldn't call them advantages. – Bergi Mar 30 '22 at 02:32
  • @Bergi - The point is that closures are "make your own" with no predefined way to declare methods or properties or be extensible. Yes, you can make your own extensible objects without using the `class` keyword as we all did before we had classes, but it's not a "standard" way where everyone does it the same way and everyone recognizes exactly what the code is doing and how its doing it. – jfriend00 Mar 30 '22 at 02:36
  • 1
    @Bravo - I'd say it more a matter of "fit" to the circumstance. In the middleware example with arguments as in `app.use(express.static(...))`, a closure is often a better fit than a class. If you're defining a Shape object and subclasses for Circle and Rect and Ellipse, then a class is a better fit. – jfriend00 Mar 30 '22 at 02:37
  • @jfriend00 I think we're talking about factory functions that return a single closure, not about factories that create objects with properties and methods (which close over state). And I'd think that parasitic inheritance is the standard way of dealing with this. Even simpler for the case where it's just a function; so simple that it doesn't have a name on its own. – Bergi Mar 30 '22 at 02:43
  • @Bergi - Yes, I thought about including factory functions that return objects with methods and properties and can be closures, but decided not to include that as it seemed beyond the scope of what was really being asked about in the question. But, there are certainly useful cases where a factory function may be a closure and can even return an instance of a class. That just isn't the type of closure example the OP showed and I didn't want to over complicate what it seemed like they were asking about. – jfriend00 Mar 30 '22 at 02:53
  • @jfriend00 Yes, and since we're excluding those complicated factories, extending closures is simple. `function countPlusTwo() { const _super = countPlusOne(); return () => (_super(), _super()); }` - I think everyone recognises what this code is doing. – Bergi Mar 30 '22 at 02:59
1

https://blog.logrocket.com/how-to-decide-between-classes-v-closures-in-javascript/

This document says class implementation uses less memory than closure; hence, classes are memory efficient.

It is mentioned that instantiating multiple new objects using class uses the same exact blueprint from memory. But, closures create a separate blueprint reference for each object creation using a function call.