Is there a way to change the execution context of a Javascript function manually at execution time?
I am not talking about changing the this
reference to point to a different object - I know this can be done with Function.prototype.call()/apply()
.
I am talking about changing variables accessible to the function, or to be more specific, granting access to variables that are outside of the scope the function is defined in.
Example:
var func;
(function () {
func = function () {
alert(test); // no variable called "test" defined, it will
// result in a ReferenceError when func() is called
}
})();
function callFunction (callee) {
var test ='foobar';
callee(); // callee does not have access to "test"
}
callFunction(func);
In this example, I'd love the function func
to be able to access the variable test
defined in callFunciton
when it is called. However due to how scope and execution contexts work in Javascript, it doesn't work that way.
I am looking for a way for callFunction
to insert a variable called test
in the execution context of the callee()
call.
In this minimal example, it is of course possible to just add test as a parameter to func().
My use-case however is a framework with a plugin infrastructure, where plugins can specify callbacks and what parameters they take - along with parameter types. The framework then takes care of converting requested data into the requested types and provide them to the callback. This should happen completely transparent to the plugin.
Pseudocode:
Plugin
function callback {
alert(user.name);
alert(number);
};
var callbackParams = [
{name : 'user', type : User},
{name : 'number', type : Number}
];
defineCallback('event', callback, callbackParams);
Framework
var on = {
event : [];
}
var User = function (name) {
this.name = name;
}
function defineCallback (event, callback, params) {
on[event].push({
callback : callback;
params : params;
});
}
function handleEvent(event) {
on[event].forEach(function (handler) {
for (param of handler.params) {
// 1) gather data
// 2) create Object of correct type as specified in
// param.type
// 3) insert variable called param.name into
// execution context of handler.callback
}
handler.callback();
});
}
So far, I found three solutions to this problem, and I like neither:
- define parameters in callback, and only define their types in callbackParams, indexed by their order in the function declaration. Disadvantage: parameters have to be declared in two places.
- use
this.paramname
instead of justparamname
in callback, and use.call()/.apply()
in `handleEvent(). Disadvantage: not transparent to plugins. - assign the variables to global scope before calling
handler.callback()
inhandleEvent()
and delete them again afterwards. Disadvantage: very ugly workaround.
Ideas?