在Javascript中从回调函数中获取对象的上下文信息

3

我有一个问题,我有一个名为“foo”的对象,需要在另一个对象“bar”上调用回调函数,并且我需要在回调函数中使用“bar”的上下文。但关键是,“foo”除了从“bar”获取其回调函数外,不应知道任何关于它的信息。

示例:

var foo = 
{
    message: "Hello foo",
    doStuff: undefined
};

var bar =
{
    message: "Hello bar",
    callback = function ()
    {
        alert(this.message);
    }

};

foo.doStuff = bar.callback;

foo.doStuff();

我知道通常你会使用"call"或"apply"来将上下文切换到bar,但在我的特定情况下,在调用foo.doStuff()时,我不再拥有关于回调来源的信息。那么是否有另一种方法来确定上下文(比如从回调函数本身中)?


4
foo.doStuff = bar.callback.bind(bar);foo.doStuff = function () {bar.callback.call(bar)};,这两种写法实际上是等价的。bind 方法在幕后所做的事情就是将函数绑定到指定的对象上,而第二种写法则是手动使用 call 方法来将函数绑定到指定的对象上。 - João Paulo Macedo
bar.callback.call(bar) 在功能上与 bar.callback() 完全相同。 - Alex Wayne
3个回答

1
还有其他方法可以确定上下文吗(比如在回调函数内部)?
没有。除非在传递回调之前进行一些额外的特定操作。如果你只有一个函数引用,通常没有上下文。但是通过一些准备工作,有一些解决方案。
您可以包装回调函数。当调用此函数时,将以完整形式调用bar.callback(),从而保留bar的上下文。
foo.doStuff = function() { bar.callback(); };

或者在现代JS引擎中,您可以将回调绑定到特定的上下文。

foo.doStuff = bar.callback.bind(bar);

或者使用underscore.js在所有JS引擎中完成此操作。

foo.doStuff = _(bar.callback).bind(bar);

如果您想要与旧引擎兼容并且不想使用整个库,可以自己创建绑定函数。

var bind = function(fn, context) {
  return function() {
    fn.call(context);
  };
};
foo.doStuff = bind(bar.callback, bar);

所有这些都说了,一个简单的包装器通常是最简单和最常见的。它几乎没有缺点,速度快,易于理解,并且可以让您对使用什么参数调用有很多控制。在这种情况下,我认为这种形式是最合适的。
foo.doStuff = function() { bar.callback(); };

谢谢,bind就是我要找的。封装到函数中也可能起作用,但由于我正在动态检索回调,因此在分配回调到其他对象时不知道需要传递哪些参数(直到调用该函数),因此无法在该点提供它们。唯一可怕的部分是MDN说Safari移动版不支持bind(尽管使用jsfiddle进行了一些快速测试似乎证明了相反的情况...)。最坏的情况是,我只需添加一个polyfill即可让其工作。 - user1601333

1

使用闭包来实现 bar。

var foo = {
    message: "Hello foo",
    doStuff: undefined
};

var bar = (function() {
    var message = "Hello bar";
    return {
        callback: function() {                
            alert(message);
        }
    };
})();


foo.doStuff = bar.callback;
foo.doStuff();
​

jsfiddle

{{链接1:jsfiddle}}


0
我会用闭包来实现。
foo.doStuff = function(){
  bar.callback();
};

如果你担心在创建回调函数和执行回调函数之间,bar的值被改变了,你可以“锁定”bar的值,但这可能有点过度。
foo.doStuff = (function(bar){
  return function(){
    bar.callback();
  }
})(bar);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接