0

有没有办法在执行时手动更改 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能够在调用它时访问test定义的变量callFunciton。但是,由于范围和执行上下文在 Javascript 中的工作方式,它不能那样工作。

我正在寻找一种方法callFunction来插入在调用test的执行上下文中callee()调用的变量。


在这个最小的例子中,当然可以将 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();
    });
}

到目前为止,我找到了三个解决这个问题的方法,我都不喜欢:

  • 在 callback 中定义参数,并且只在 callbackParams 中定义它们的类型,按它们在函数声明中的顺序索引。缺点:参数必须在两个地方声明。
  • 使用this.paramname而不是仅paramname在回调中使用,并.call()/.apply()在 `handleEvent() 中使用。缺点:对插件不透明。
  • 在调用之前将变量分配给全局范围,handler.callback()然后handleEvent()再次删除它们。缺点:非常难看的解决方法。

想法?

4

1 回答 1

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);

于 2016-06-04T18:58:29.660 回答