Skip to content

Instantly share code, notes, and snippets.

@suyanhanx
Forked from hax/index.js
Last active September 1, 2022 11:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save suyanhanx/48e77d6ace6ea4ca8c6c12ad30ac59cc to your computer and use it in GitHub Desktop.
Save suyanhanx/48e77d6ace6ea4ca8c6c12ad30ac59cc to your computer and use it in GitHub Desktop.
JS trick to mimic C# obj.onevent += delegate
const HandlerID = Symbol()
export function defineEvent(obj, name) {
const handlers = new Set()
const fn = function () {
for (const handler of handlers) {
try {
handler()
} catch (e) {
Promise.reject(e)
}
}
}
fn[HandlerID] = 0
Object.defineProperty(obj, name, {
get() { return handlers.size ? fn : null },
set(v) {
if (v === null) {
// console.log('=', v)
handlers.clear()
} else if (typeof v == "function") {
// console.log('=', v)
handlers.clear()
handlers.add(v)
} else if (v > 0) {
// console.log('+=', v)
v = handlerMaps.get(v)
if (!v) throw new TypeError()
handlers.add(v)
} else if (v < 0) {
// console.log('-=', v)
v = handlerMaps.get(-v)
if (!v) throw new TypeError()
handlers.delete(v)
} else {
throw new TypeError()
}
},
})
}
const handlerMaps = new Map()
Function.prototype.valueOf = function () {
return this[HandlerID] ?? genHandlerID(this)
}
function genHandlerID(fn) {
Promise.resolve(fn).then(disposeHandlerID)
let id
do { id = Math.random() }
while (handlerMaps.has(id))
handlerMaps.set(id, fn)
fn[HandlerID] = id
return id
}
function disposeHandlerID(fn) {
handlerMaps.delete(fn[HandlerID])
fn[HandlerID] = null
}
import { defineEvent } from "./index.js"
import assert from "node:assert/strict"
const x = {}
defineEvent(x, "onChange")
const handlers = [
() => console.log(0),
() => console.log(1),
() => console.log(2),
]
assert.equal(x.onChange, null)
x.onChange += handlers[0]
assert.notEqual(x.onChange, null)
x.onChange() // output 0
x.onChange += handlers[1]
x.onChange += handlers[2]
x.onChange -= handlers[0]
x.onChange += handlers[1]
x.onChange() // output 1, 2
x.onChange -= handlers[1]
x.onChange -= handlers[2]
assert.equal(x.onChange, null)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment