WeakMap utility functions and related patterns
npm install weaken-itbash
npm i weaken-it
`
$3
`html
`
:wrench: How it works
At its core it's just a temporary namespaced key-value store built on top of native js WeakMap and Map, using a set of personal conventions enforced by weakenIt() function. Both WeakMap and Map were chosen over plain objects for their advantages in terms of r/w speed and key flexibility.
* Creates a WeakMap, wStore
* WeakMap ensures that each instance is stored once and its associated context expires with it
* weakenIt ensures that each Map context is stored / recreated only once and always reused
* Then weakenIt, or even shorter wit, stores / gets any key-value from the related context
* When reference is lost or wStore.prototype.deleted || wDel, its context gets garbage-collected
:thinking: Why
I was very excited about WeakRef and FinalizationRegistry coming to javascript but both their behaviours are not yet guaranteed, making them very hard to reason about, at least for me.
:ring_buoy: WeakMap and WeakSet to the rescue!
* They ensure stored data will expire after the bound instance, or will always be available as long the associated reference exists
* They enable patterns I reach for when I need to extend libraries, js natives, work with dom, store temporary data or when I'm generally concerned about potential memory leaks
* It can safely bridge context data inside closures or where unreachable
* They're fast, native, memory-efficient by nature, fully supported and reliable
* They give me peace of mind :relieved:
:muscle: Usage
For more examples, please refer to tests folder.
`js
import { weakenIt } from 'weaken-it'
// augment an external library or native
class Example extends SomeLibraryOrNative {
constructor(extraData, ...libraryRequired) {
super(...libraryRequired)
// extraData never outlives the instance
weakenIt(this, 'temp', extraData + 'Example constructor')
}
overridden(...methodArgs) {
// bridged inside
const extraData = weakenIt(this, 'temp')
doSomethingWith(temp)
// still works without modifying the original implementation
return SomeLibraryOrNative.prototype.overridden.apply(this, methodArgs)
}
}
let exampleInstance = new Example(
'extra data from: ',
'library needed data'
)
function useExtraData() {
console.log(weakenIt(example, 'temp'))
}
useExtraData()
// extra data from: Example constructor
example = null
useExtraData()
// undefined (gc'ed)
``