Skip to content

Instantly share code, notes, and snippets.

@isaacs
Last active February 23, 2021 19:34
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 isaacs/7a5cc204bdac401e35b13b8e63c17cba to your computer and use it in GitHub Desktop.
Save isaacs/7a5cc204bdac401e35b13b8e63c17cba to your computer and use it in GitHub Desktop.
const unbound = Symbol('unbound')
const bindMethod = (obj, fn) => {
const value = fn[unbound] || fn
return Object.assign(value.bind(obj), { [unbound]: value })
}
const bindObjMethods = obj => {
const proto = Object.getPrototypeOf(obj)
for (const name of Object.getOwnPropertyNames(proto)) {
if (name === 'constructor')
continue
const descriptor = Object.getOwnPropertyDescriptor(proto, name)
if (('value' in descriptor) && typeof descriptor.value === 'function') {
descriptor.value = bindMethod(obj, descriptor.value)
Object.defineProperty(obj, name, descriptor)
}
if (typeof descriptor.get === 'function' || typeof descriptor.set === 'function') {
const { get, set } = descriptor
if (typeof get === 'function') {
descriptor.get = () => {
const value = get.call(obj)
return typeof value !== 'function' ? value
: bindMethod(obj, value)
}
}
if (typeof set === 'function') {
descriptor.set = value => {
value = typeof value !== 'function' ? value
: bindMethod(obj, value)
set.call(obj, value)
}
}
}
Object.defineProperty(obj, name, descriptor)
}
}
class A {
method () {
return this
}
}
class B {
_method () {
return this
}
get method () {
return this._method
}
set method (value) {
this._method = value
}
}
const a = Object.assign(new A(), { a: 1 })
bindObjMethods(a)
const { method: aMethod } = a
const b = Object.assign(new B(), { b: 2 })
bindObjMethods(b)
const { method: bMethod } = b
console.log('a.method()', a.method())
console.log('aMethod()', aMethod())
console.log('b.method()', b.method())
console.log('bMethod()', bMethod())
const c = { c: 3 }
b.method = function () { return [this, c] }
const { method: changedBMethod } = b
console.log('changed b.method()', b.method())
console.log('changedBMethod()', changedBMethod())
const bChild = Object.assign(Object.create(b), {bChild: 4})
bindObjMethods(bChild)
const { method: bChildMethod } = bChild
console.log('bChild.method()', bChild.method())
console.log('bChildMethod()', bChildMethod())
/*
a.method() A { a: 1 }
aMethod() A { a: 1 }
b.method() B { b: 2 }
bMethod() B { b: 2 }
changed b.method() [ B { b: 2 }, { c: 3 } ]
changedBMethod() [ B { b: 2 }, { c: 3 } ]
bChild.method() [ B { bChild: 4, b: 2 }, { c: 3 } ]
bChildMethod() [ B { bChild: 4, b: 2 }, { c: 3 } ]
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment