Recursive function binding in a JavaScript object
Function.prototype.bind
in some edge cases; binding all functions in an object to the same this
value regardless of depth is one of them.The example I have in mind is the building of a Vue.js plugin such as this one:
function install(Vue) {
Vue.mixin({
beforeCreate() {
this.$myPlugin = {
aMethod() {
console.log(this);
},
yet: {
anotherMethod() {
console.log(this);
}
}
};
}
});
}
export default { install };
Fairly logically, setting it up through
Vue.use(MyPlugin)
and calling this.$myPlugin.aMethod
and this.$myPlugin.yet.anotherMethod
yields a reference to the plugin object itself twice, which might not be what you want depending on what the plugin is supposed to do.In such a situation, we therefore need to write a recursive binding function, which luckily is not all that hard:
function recursiveBind(obj, that) {
return Object.keys(obj).reduce((acc, key) => {
switch (typeof obj[key]) {
case "object":
return { ...acc, [key]: recursiveBind(obj[key], that) }; // recurse
case "function":
return { ...acc, [key]: obj[key].bind(that) }; // bind
}
return { ...acc, [key]: obj[key] }; // leave untouched
}, {});
}
All that remains to do then is to wrap our plugin object declaration with it:
function install(Vue) {
Vue.mixin({
beforeCreate() {
this.$myPlugin = recursiveBind({
aMethod() {
console.log(this);
},
yet: {
anotherMethod() {
console.log(this);
}
}
}, this);
}
});
}
And
this
now correctly refers to our Vue
instance! Please share your plugin tips in the comment section, if any!