How to monkey patch a recursive function

395 Views Asked by At

I'm using a library () that exposes a function clone() that is called recursively for all the nodes in a hierarchy.

If I monkey patch the function to execute some additional code, this will be executed multiple times.

Instead, I need to execute my code at the end of the whole recursive calls, but I can't find a way to do it.

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

If I try this way I get "my stuff" executed multiple times.

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

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

I need to "override" the clone method so that after all its recursive calls, I can execute my code.

2

There are 2 best solutions below

4
On BEST ANSWER

You can achieve that by temporarily restoring the original function before launching it. And when it is finished, you set your trap again, and perform your post processing:

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;
}
1
On

I'd still go with a simple flag to determine wether I'm inside a recursion or not.

//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 is a flag, specific for this single implementation. Maybe you want to wrap this code in a block or an iife to ensure that the variables are not accessible from outside of your clone-method.


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

You'll find most about v8 optimizations on google, but most modern browsers do similar stuff. I just googled and came across this article Performance Tips for JavaScript in V8. It's a bit older, but I think it's a good point to start getting an understanding on the kind of optimizations that JS engines do to your code to make it faster.

But as the article it mentions, don't loose yourself in (pointless) optimizations.