【发布时间】:2016-06-04 18:43:50
【问题描述】:
有没有办法在执行时手动更改 Javascript 函数的执行上下文?
我不是谈论将 this 引用更改为指向不同的对象 - 我知道这可以通过 Function.prototype.call()/apply() 完成。
我说的是更改函数可访问的变量,或者更具体地说,授予对函数定义范围之外的变量的访问权限。
例子:
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);
在此示例中,我希望函数 func 在调用时能够访问在 callFunciton 中定义的变量 test。然而,由于作用域和执行上下文在 Javascript 中的工作方式,它不是那样工作的。
我正在寻找一种方法让callFunction 在callee() 调用的执行上下文中插入一个名为test 的变量。
在这个最小的例子中,当然可以将 test 作为参数添加到 func()。
然而,我的用例是一个带有插件基础设施的框架,插件可以指定回调和它们采用的参数 - 以及参数类型。然后框架负责将请求的数据转换为请求的类型并将它们提供给回调。这应该对插件完全透明。
伪代码:
插件
function callback {
alert(user.name);
alert(number);
};
var callbackParams = [
{name : 'user', type : User},
{name : 'number', type : Number}
];
defineCallback('event', callback, callbackParams);
框架
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();
});
}
到目前为止,我找到了三个解决这个问题的方法,我都不喜欢:
- 在回调中定义参数,并且只在回调参数中定义它们的类型,在函数声明中按它们的顺序索引。缺点:必须在两个地方声明参数。
- 在回调中使用
this.paramname而不是只使用paramname,并在`handleEvent() 中使用.call()/.apply()。缺点:对插件不透明。 - 在
handleEvent()中调用handler.callback()之前将变量分配给全局范围,然后再次删除它们。缺点:非常难看的解决方法。
想法?
【问题讨论】:
-
简短回答,否,除非变量在作用域内,否则函数无法访问变量,因此要么将变量作为参数传递,要么使它们可用于作用域如果你不将所有内容都包装在 IIFE 中,这应该是可行的
-
你必须重新评估()函数代码来重新评估闭包。
-
我的“想法”是你重新考虑你的设计。这完全是错误的。这是反直觉的,对于语言(可能对于任何语言)来说都是不自然的,它是不可测试的(对于插件开发人员来说),最糟糕的是,简单的解决方案(显式声明的参数)拥有你需要的一切而没有任何真正的缺点。跨度>
-
对于您的用例,您应该使用
function callback(user, number) { … }并按照callbackParams中给出的顺序传递值。如果您不需要它们,您甚至可以删除name并指定type。 -
@JohannesH.:您可以在视觉上将它们放在一起,例如
callback.types = [User, Number]; ¶ function callback(user, number) { ¶ …
标签: javascript function scope executioncontext