Search code examples
javascriptfunctional-programmingthisdynamic-rebinding

Temporarily rebind then safely re-attach library method


I'm building a module in the context of an existing library. Some of the library's functionality — specifically, LIBRARY.module.add (for the sake of example: the actual functionality's much more elaborate) —, which can be triggered in all sorts of scenarios, will destroy my module's UX, so I need to interrupt it to take account of my module's esoteric concerns.

I'm not allowed to re-write any part of the original library, and I'm not allowed to duplicate functionality which is supposedly covered by the library.

Existing code is something like this:

LIBRARY.moduleX = {
    two      : 2,
    addToTwo : function(addAnd){
        return this.two + addAnd;
    }
}

A key concern here is that LIBRARY's modules are all written in literal object notation and their methods rely on this. Another concern is that the code base is continuously in flux. I can't rely on addToTwo's arity or anything like that (in case someone extends it to take multiple operands or whatever).

So I've written this to execute as part of my component's initialization:

void function handleModuleX(){
    // Keep a reference before rebinding
    var LIBRARY_moduleX_addToTwo = LIBRARY.moduleX.addToTwo;

    // Restores the original binding
    function rebind(){
        LIBRARY.moduleX.addToTwo = function(){
            return LIBRARY_moduleX_addToTwo.apply(LIBRARY.moduleX, arguments);
        }
    }

    // Rebind to consider local logic
    LIBRARY.moduleX.addToTwo = function handleEsotericLogic(){
        if(unresolvedConcerns){
            stuff();
        }
        else {
            rebind();

            LIBRARY.moduleX.addToTwo();
        }
    }
}();

This appears to work. My concern is ultimately with the safety and legibility of the rebinding:

  • Is this technique bulletproof, inasmuch as it doesn't make any assumptions about addToTwo?
  • Is this as close as I can get to restoring the original binding?
  • Can I achieve the same functionality without nesting so many scopes (obviously rebind can be written in to the else statement — it's only hoisted out for clarity)?

Solution

  • A bit more research lead me to underscore's bind method, which does basically the same thing I did to polyfill ECMAScript 5's native Function method of the same name — which appears to be the only way I can avoid the 2 closures involved in the implementation above. So now my code is more verbose — because I just really didn't like the idea of calls on the library's method bouncing through my code on stack trace if possible (it's like I never touched it!):

    function rebind(){
        if(Function.prototype.bind){
            LIBRARY.moduleX.addToTwo = LIBRARY_moduleX_addToTwo.bind(LIBRARY.moduleX);
        }
        else {
            LIBRARY.moduleX.addToTwo = function(){
                return LIBRARY_moduleX_addToTwo.apply(LIBRARY.moduleX, arguments);
            }
        }
    }