在重绑定函数引用时避免递归

Avoid recursion in rebinding function reference

本文关键字:递归 引用 绑定 函数      更新时间:2023-09-26

X多次试图调用其方法foo,从而严重损害了我的插件Y的用户体验。我的插件Y引入了任意逻辑shouldFooExecute,必须在X.foo的最终结果发生之前考虑。然而,当用户通过Y的旅程(发生在一个模态窗口中)完成时,X应该能够继续,好像什么都没有发生。

// This is an external library. I can't modify and shouldn't overwrite it.
x = {
  // A method that completely screws my plugin
  foo: function(){
    /* nasty stuff */
  }
}
// This is my widget!
y = {
  // Init function, called when my plugin boots
  init: function(){
    // This scope handles the x.foo problem
    void function rebindFoo(){
      // Internal state
      var shouldFooExecute = false;
      // I need to be able to refer back to the original foo after I've temporarily rebound it
      var x_foo = x.foo;
      // Re-attach foo to its original definition & context
      function rebindFooToX(){
        // ECMAScript 5 browsers are fine!
        if(Function.prototype.bind){
          // x.foo is literally rebound to pretty much exactly what it was
          x.foo = x_foo.bind(x);
        }
        // Others not so good when this function executes a second time
        else {
          x.foo = function rebound_foo(){
            // An extra scope! Horrible. And it's recursive!
            return x_foo.apply(x, arguments);
          }
        }
      }
      x.foo = function y_foo(){
        // Stop and consider y's esoteric logic
        if(shouldFooExecute){
          // If it's fine, we rebind everything
          rebindFooToX();
          // This will have the intended effect
          x.foo();
        }
      }
    }
  }
}

当我的插件在不支持bind的浏览器上重新初始化时,问题就出现了。x.foo最终引用rebound_foo,这是循环的。我可以编写任何类型的逻辑来避免递归,并在存在的情况下使用现有的rebound_foo ?

您可以使用https://github.com/kriskowal/es5-shim将Function.prototype.bind方法添加到本地不支持它的浏览器

这是7个月后的事实,所以这个问题可能是OBE,但我想指出,这取决于X是如何定义的,你可以尝试继承:

var x = function() {
    this.foo = function() {
        console.log("from x");
    };
    this.bar = function() {
        console.log("from x");
    };
}
var y = function() {
    this.foo = function() {
        console.log("from y");
    }
}
y.prototype = new x();
var test = new y();
test.foo(); // will output: from y
test.bar(); // will output: from x