如何猴子修补递归函数

How to monkey patch a recursive function

我正在使用一个库() that exposes a function clone() 对层次结构中的所有节点递归调用。

如果我猴子修补函数以执行一些额外的代码,这将被执行多次。

相反,我需要在整个递归调用结束时执行我的代码,但我找不到执行此操作的方法。

pc.Entity.prototype.clone = function() {
    ... some code
    // then for each child it calls itself
}

如果我尝试这种方式,我会 "my stuff" 执行多次。

pc.Entity.prototype.cloneOriginal = pc.Entity.prototype.clone;

pc.Entity.prototype.clone = function() {
    var c = this.cloneOriginal();
    // do my stuff
    return c;
}

我需要 "override" clone 方法,以便在所有递归调用之后,我可以执行我的代码。

我仍然会使用一个简单的标志来确定我是否在递归中。

//no need to store that function on the prototype itself
const cloneOriginal = pc.Entity.prototype.clone;

let inRecursion = false;
pc.Entity.prototype.clone = function() {
    //just pass through the call to the original function.
    if(inRecursion)
        return cloneOriginal.call(this);

    inRecursion = true;
    var c = cloneOriginal.call(this);
    inRecursion = false;

    // do my stuff
    return c;
}

inRecursion 是一个标志,特定于此单个实现。也许您想将此代码包装在一个块或一个 iife 中,以确保无法从您的克隆方法外部访问这些变量。


could you point me to some more info about the optimization you are speaking about. What should I google?

您会在 google 上找到关于 v8 优化 的大部分信息,但大多数现代浏览器都做类似的事情。我刚刚 googled 看到了这篇文章 Performance Tips for JavaScript in V8。它有点旧,但我认为开始了解 JS 引擎对您的代码所做的优化以使其更快是一个很好的起点。

但是正如文章中提到的那样,不要在 (毫无意义) 优化中放松自己。

您可以通过在启动之前临时恢复原始功能来实现。完成后,您再次设置陷阱,并执行 post 处理:

const orig_clone = pc.Entity.prototype.clone; // Save original clone
// Set trap:
pc.Entity.prototype.clone = function patched_clone(...args) {
    pc.Entity.prototype.clone = orig_clone; // Restore original function
    let result = this.clone(...args); // Execute it
    // All is done, including recursion. 
    pc.Entity.prototype.clone = patched_clone; // Set trap again
    // Your code comes here
    console.log('post processing');
    return result;
}