【问题标题】:How to extend method (monkey patch) without a temporary variable?如何在没有临时变量的情况下扩展方法(猴子补丁)?
【发布时间】:2015-03-24 21:12:04
【问题描述】:

一定是我的问题措辞有误,因为我找不到关于似乎经常出现的问题的现有问题。

我有一个班级Foo

var Foo = function () {
    return {
        a: function () {}
    };
};

我有另一个类 BarFoo 的实例实例化:

var Bar = function (foo) {
    // Does something with foo.  
};

我想扩展 Foo 实例以使 Bar 以不同的方式工作:

var Bar = function (foo) {
    foo.a = function () {
        return foo.a.apply(this, arguments);
    };

    // Does something with foo.  
};

按照我的方式做,会导致RangeError: Maximum call stack size exceeded。有没有办法在没有临时变量的情况下扩展方法本身?

这是使用额外变量的方法:

var Bar = function (foo) {
    var originala;

    originala = foo.a;

    foo.a = function () {
        return originala.apply(this, arguments);
    };

    // Does something with foo.  
};

【问题讨论】:

  • 为什么不想使用临时变量?更好的是,你想用这个来完成什么?这似乎有点可疑。

标签: javascript node.js


【解决方案1】:

问题:

您正在超出最大调用堆栈,因为您一遍又一遍地从自身调用相同的函数(递归)。

原因:

当您构造Foo 时,它会获得一个分配给其属性a 的函数。一切都很好。

接下来,您构造Bar 并尝试通过将对象上的函数替换为您自己的函数来修改Foo.a 的行为。但是,您希望在新函数的主体中,Foo.a 仍将包含原始函数。反之亦然 - Foo.a 现在包含您的新修改函数。这就是为什么当你调用它时,它会一直调用它自己,直到你点击maximum stack size limit

发生这种情况是因为变量的值在执行时被解析,并且您的新函数在分配给Foo.a 后执行得很好。此对象的原始功能丢失。

解决办法:

使用prototypes。我不会详细介绍如何使用原型继承,因为有很多浮动。

请注意,您的方法是有效的,而且通常是唯一的。您只需在某处保留对原始函数的引用,以便以后调用它。

【讨论】:

  • 扩展原型会影响Foo 的所有实例。我正在修补foo 的现有实例以在特定域中表现不同。这是对问题的准确解释。我希望有某种名称引用可以避免临时变量。
  • 您可以将普通功能放到原型中,然后为每个实例添加猴子补丁。您也可以使用命名函数,但为了访问它,您需要在类之外定义它,在我看来这可能看起来很难看...
【解决方案2】:

使用classes 时,这变得非常容易。

class Foo {
    a(){
        return /* Something */
    }
}

class Bar extends Foo {
    a(){
        /* Do something else */
        return super.a()
    }
}

在 6 年前提出这个问题时,大多数浏览器(如果有的话)都无法做到这一点,但 every modern browser now supports classes

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-04-08
    • 1970-01-01
    • 2015-04-17
    • 2012-08-19
    • 2011-09-11
    • 1970-01-01
    • 2023-03-27
    • 2011-04-22
    相关资源
    最近更新 更多