【问题标题】:Javascript: Execute function with different execution contextJavascript:使用不同的执行上下文执行函数
【发布时间】: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 中的工作方式,它不是那样工作的。

我正在寻找一种方法让callFunctioncallee() 调用的执行上下文中插入一个名为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


【解决方案1】:

您可以使用with 语句。请注意,在严格模式下它很慢并且被禁止。

var func;
(function () {
  func = function func() {
    with(func.variables) {
      console.log(test);
    }
  }
})();
function callFunction (callee) {
  callee.variables = {test: "foobar"};
  callee();
  callee.variables = null;
}
callFunction(func);

【讨论】:

  • 感谢您的建议!我完全忘记了with,因为我已经有很多年没有使用它了……我喜欢将变量分配给回调函数的属性的方法,我还没有考虑过这个。我将不得不指定回调可以通过这种方式访问​​其参数的插件基础结构 - 不过,如果插件开发人员在其中使用 with 不在我的责任范围内。
  • 不过,callee.variables 只是将变量对象作为参数传递给函数的一种相当粗略的解决方法。插件是否使用with 甚至不是您的决定。
猜你喜欢
  • 2014-01-20
  • 1970-01-01
  • 2016-05-12
  • 2023-03-24
  • 1970-01-01
  • 2015-01-28
  • 2022-11-27
相关资源
最近更新 更多