Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Weak maps and weak sets in terms of private symbols
const _wmSymbol = Symbol.private("wmSymbol")
const _wsSymbol = Symbol.private("wsSymbol")
const call = Function.call.bind(Function.call)
const hasOwn = Function.call.bind({}.hasOwnProperty)
const getOwn = Object.getOwnPropertyDescriptor
const TE = TypeError
const checkMapThisKey = makeChecker("WeakMap", "weak map", _wmSymbol)
const checkSetThisKey = makeChecker("WeakSet", "weak set", _wsSymbol)
function makeChecker(name, human, symbol) {
return (inst, key, method) => {
if (!hasOwn(inst, _symbol)) {
throw new TE(
"`" + name + ".prototype." + method +
"` called on incompatible receiver"
)
}
if (typeof key !== "object") {
throw new TE("Invalid value used as " + human + " key")
}
}
}
class WeakMap {
constructor(iter) {
this[_wmSymbol] = Symbol.private()
const set = this.set
for (const [key, value] of iter) call(set, this, key, value)
}
delete(key) {
checkMapThisKey(this, key, "delete")
return delete key[this[_wmSymbol]]
}
get(key) {
checkMapThisKey(this, key, "get")
const desc = getOwn(key, this[_wmSymbol])
return desc != null ? desc.value : void 0
}
has(key) {
checkMapThisKey(this, key, "has")
return hasOwn(key, this[_wmSymbol])
}
set(key, value) {
checkMapThisKey(this, key, "set")
key[this[_wmSymbol]] = value
return this
}
}
class WeakSet {
constructor(iter) {
this[_wsSymbol] = Symbol.private()
const set = this.set
for (const item of iter) call(set, this, item)
}
delete(key) {
checkSetThisKey(this, key, "delete")
return delete key[this[_wsSymbol]]
}
has(key) {
checkSetThisKey(this, key, "has")
return hasOwn(key, this[_wsSymbol])
}
add(key) {
checkSetThisKey(this, key, "add")
key[this[_wsSymbol]] = true
return this
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment