class
in JavaScript
Stop writing This writing is to try to convince you to stop doing this:
class Person {
constructor (name: string) {
this.name = name
}
sayHello () {
return `Hello ${this.name}`
}
sayBye () {
return `Bye ${this.name}`
}
}
and do this instead:
const sayHello = name => `Hello ${name}`
const sayBye = name => `Bye ${name}`
Advantages To Switching
Can have multiple files
class
: In the example, the class
is very small and simple. Real class
s are often >100 lines long. It can get very messy and hard to understand what is going on.
No class
: You can split your code into however many files you want. The file name can make it clear what that file's code is doing, and it's easier to understand when you see less lines of code.
Example:
sayHello.js
// Say hello
sayBye.js
// Say bye
Code Splitting
When you write a class
, sometimes not all of its methods are used. class
is harder to do code splitting than functions. It really bothers me when I am using a library which has a class
with a lot of methods that I'm not going to use:
class Counter {
set () {}
reset () {}
add () {}
addOne () {}
subtractOne () {}
subtract () {}
}
class
Can't extend >1 Here is an example of two usefull class
s:
class MultiKeyMap extends Map {
// Methods overrided to use multiple keys
get () {}
set () {}
has () {}
delete () {}
}
class DefaultedMap {
constructor (getDefault) {}
// Calls `getDefault` if no key
get () {}
}
What if you wanted a DefaultedMultiKeyMap
? There is no way to do this that isn't messy. Here is a messy way, based on this StackOverflow answer:
const getDefaultedMap = BaseMap => class extends BaseMap {
// Defaulted map overrides
}
const DefaultedMultiKeyMap = getDefaultedMap(MultiKeyMap)
One problem with this is that it relies on the defaulted map to be a function which returns a custom class
. If you're using a js library and it's a class, it probably doesn't have a way to be based off of two classes.
Here is what you can do using flexible functions:
multiKeyMap/get.js
const get = (keys, internalGet) => {}
defaultedMap/get.js
const get = (key, defaultFn, internalGet) => {}
normalMap/get.js
const get = (map, key) => map.get(key)
Your code
const normalMap = new Map()
getOrDefault(['key1', 'key2'], keys => getMultiKey(keys, keys => normalMapGet(normalMap, keys)))
With this way the only data you have to store is a normal Map
!
Using flexible functions
The examples will use TypeScript because it's easier to understand the data types.
Emitter example
There are so many different emitters you can use in JavaScript. The most common emitters are Node.js EventEmitter
and eventemitter3
. Both of these emitters are class
. This example will show a very flexible emitter, which is emitter logic which you can wrap in anything.
type ForEachCallback<ItemData> = (itemData: ItemData) => void
type ForEach<ForEachData, ItemData> = (data: ForEachData, callback: ForEachCallback<ItemData>) => void
type Listener<T extends unknown[]> = (...inputs: T) => void
const emit = <ForEachData, T extends unknown[]>(
forEachData: ForEachData,
forEach: ForEach<ForEachData, Listener<T>>
): void => {
forEach(forEachData, listener => listener())
}
Things that make this emitter very flexible:
- No requirement of needing a
Set
,Array
, orMap
to store listeners. Instead of usingArray.prototype.forEach()
, it lets you customize the forEach function. - No requirement of how you add / remove listeners
Example usages of emit
:
With Array
const arrayForEach: ForEach<unknown[], unknown> = (arr, callback) => arr.forEach(callback)
emit(myArrayOfListeners, arrayForEach)
With Set
const setForEach: ForEach<Set<unknown>, unknown> = (set, callback) => set.forEach(callback)
emit(mySetOfListeners, arrayForEach)
Contributing
class
Adding a bad thing about not using Create an issue with a reason that is supporting class
class
Adding another reason to not use Create an issue or pull request
Talking about this topic
Open a discussion