I wanted to create a function that I can add actions to later. I tried this:
Function.prototype.appendAction = function(action) {
let _ogFn = this
return function(...args) {
_ogFn(...args)
action()
}
}
function a() {
console.log("foo")
}
a()
a = a.appendAction(() => console.log("bar"))
a()
This does work, but how can I make it change the function automatically? I want to make it work like this:
a()
a.appendAction(() => console.log("bar")) //note it doesn't have the "a = "
a() //changed function
CodePudding user response:
If you just want to call it immediately:
Function.prototype.appendAction = function(action) {
let _ogFn = this
return (function(...args) {
_ogFn(...args)
action()
})()
}
function a() {
console.log("foo")
}
a.appendAction(() => console.log("bar"))
That is the immediately invoked function expression (IIFE) pattern
CodePudding user response:
For your purposes you could use eval:
First, grab the user input however you are handling it and parse it as a string.
Then use eval like so:
let userInput = 'console.log("hello world")';
const callUserFunction = (action) => {
eval(`function fn(){${action}}`);
fn();
}
callUserFunction(userInput);
Be aware that allowing a user to write or JS is a security risk, which can open doors to all kinds of attacks, so in most scenarios, I would discourage doing so
CodePudding user response:
Depending on your scenario you could create a function decorator. This would mean defining a function (for example fnMod
) that accepts a function fn
and returns a decorated version that executes some before and after hooks.
const a = fnMod(() => {
console.log("foo");
});
a();
a.appendAction(() => console.log("bar"));
a();
function fnMod(fn) {
const before = [];
const after = [];
function hookable(...args) {
before.forEach(fn => fn.apply(this, args));
const result = fn.apply(this, args);
after.forEach(fn => fn.apply(this, args));
return result;
};
hookable.prependAction = (fn) => {
before.unshift(fn);
}
hookable.appendAction = (fn) => {
after.push(fn);
}
return hookable;
}
You might want to tweak it to your liking. Currently both this
and all arguments passed to the decorated function are forwarded to all hooks, which might or might not be desirable.