I do a lot of full-stack JS work, and I generally follow an approach like this when creating a file with encapsulated logic:
export const SOME_KEY_TO_STATE = 'some-key';
export const ANOTHER_KEY_TO_STATE = 'another-key';
let moduleState = {};
export function modifyState(someArg) {
// ... do some logic
// ... perhaps derive some new value based off of logic
const newValue = derivedNewValue;
moduleState[someKey] = newValue;
}
export function getSomeState(aKey) {
// ... do some sanity checking?
const initialValue = moduleState[aKey];
// ... calculate value based on some conditions?
const finalValue = calculatedValue;
return moduleState
}
I've also used classes occasionally, which essentially provide the same structure, except the module state would be inside the class as an instance variable, and possibly static variables for those exported constants:
export default class SomeThing {
static SOME_KEY = '';
state = {};
modifyState(arg) { ... }
getSomeState() { ... }
}
My preferred approach is the first one, primarily because I can import only what I need in other parts of the code without having an entire object floating around (along with it's state and other methods that I may not use <-- is this statement accurate or am I completely off?). Also, if I want to reference functions within a context, I can always do import { * as someName } from myModule
I'm curious though, is there a benefit that I'm not aware of to using a class rather than the first approach I outlined?
Classes in JavaScript are syntactic sugar over the prototype-based inheritance model which we use to implement OOP concepts. Thus the introduction of classes in JS made it easier for developers to build software around OOP concepts.
As a rule of thumb, when you have a set of data with a specific structure and you want to perform specific methods on it, use a class. That is only valid, however, if you use multiple data structures in your code. If your whole code won't ever deal with more than one structure.
Classes are a template for creating objects. They encapsulate data with code to work on that data. Classes in JS are built on prototypes but also have some syntax and semantics that are not shared with ES5 class-like semantics.
One key distinction between functions and classes was highlighted in this talk which suggests that a function is a behavior that can carry data while, inversely, a class is data that can carry behavior.
let moduleState = {};
This is global state, which is best to be avoided. While it might be encapsulated well in your module, it is a static variable, essentially a singleton - it exists only once in your entire application, being created when the module is loaded.
There are some cases where this might be appropriate, but in general don't use singletons!
A class
solution has the clear advantage that you can instantiate it as many times as you want, in any place where you want (e.g. tests). So make sure to understand this difference, then choose the appropriate pattern.
I like the first one, primarily because I can import only what I need in other parts of the code without having an entire object floating around (along with it's state and other methods that I may not use)
This is pretty off indeed. You always have the complete module object and state and functions floating around in your application, it's not like they get optimised away. Sure, when you don't import
them explicitly they're not around in your scope, but having a class
instance available doesn't really hurt either. If you don't call all of its methods, it's just like not importing all functions from your module.
The syntactic difference between calling a plain function or invoking a method on an object really is a minor detail that should not affect your decision. You can always sidestep it anyway by namespace-importing the module or destructuring the object.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With