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
CodePudding user response:
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.
CodePudding user response:
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.
CodePudding user response:
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:
- There's defined syntax in the language
- You can sub-class a class to extend it
- You can more easily have many properties and many methods.
- Methods are automatically non-enumerable and run in strict mode.
- 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. - For object with a lot of methods there's some space-savings benefit to the prototype that a
class
uses. - 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:
- The data in the closure is complete private. Nobody can get to it from outside the closure.
- 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.