重新连接一个javascript函数

时间:2013-12-11 19:20:40

标签: javascript dependency-injection

假设我有一个名为fna()的函数可以执行一个简单的操作,例如:

var fna = function(ar) {
     console.log("argument:",ar);
     return "return value is argument too:"+ar;
}

fna()是由其他开发人员编写的,我无法访问它,他没有打扰任何事件,当它被调用时,我必须要注意它。希望他的方法可以通过window.fna()

访问

我想要执行一些额外的代码,假设添加此console.log

var fna = function(ar) {
     console.log("Hola, I am some additionnal stuffs being rewired");
     console.log("argument:",ar);
     return "return value is argument too:"+ar;
}

我希望即使从fnb()通过代码的其他部分调用它也会执行此操作。

var fnb = function() {
    return fna("Bonjour, I am fnb and I call fna");
}

以下是我使用utils.rewire()方法找到的方法。 utils只是一些实用程序带,可以作为插件添加到您喜欢的框架中。不幸的是它只适用于Firefox

var utils = utils || {};
// let's rewire a function. i.e. My.super.method()
utils.rewire = function(functionFullName, callback) {
    var rewired = window[functionFullName];
    console.log("%s() is being rewired",functionFullName)

    window[functionFullName] = function() {
            callback();
            return rewired.apply(this, arguments);
    }
}

像这样使用它。

utils.rewire("fna",function(){
    console.log("Hola, I am some additionnal stuffs being rewired");
});

这似乎有效,如this jsbin所示,但(这是我的问题:) 如何重新布线 obja.fna()

var obja = {
     fna = function(ar) {
         console.log("argument:",ar);
         return "return value is argument too:"+ar;
     }
};

我无法重新使用some.object.method()方法。

额外奖励问题:有更清洁的方法吗?开箱即用的简洁和神奇的图书馆?

5 个答案:

答案 0 :(得分:4)

rewire重构为rewireMethod函数,该函数作用于任何给定对象:

var utils = utils || {};
utils.rewireMethod = function (obj, functionName, prefunc) {
    var original = obj[functionName];

    obj[functionName] = function () {
        prefunc();
        return original.apply(this, arguments);
    };
};

请注意,rewire现在可以写为:

utils.rewire = function (functionName, prefunc) {
    utils.rewireMethod(window, functionName, prefunc);
};

然后你只需将其称为:

utils.rewireMethod(obja, "fna", function () {
    console.log("Hola, I am some additionnal[sic] stuffs being rewired");
});

请注意,如果您使用window.ideeli.Search.init()等方法,则无需任何特殊操作。在这种情况下,对象为window.ideeli.Search,方法名称为init

utils.rewireMethod(window.ideeli.Search, "init", function () {
    console.log("Oh yeah, nested objects.");
});

答案 1 :(得分:0)

rewire添加一个参数,该参数是包含该函数的对象。如果它是全局函数,请传入window

var utils = utils || {};
// let's rewire a function. i.e. My.super.method()
utils.rewire = function(object, functionName, callback) {
    var rewired = object[functionName];
    console.log("%s() is being rewired", functionName)

    object[functionName] = function() {
            callback();
            return rewired.apply(this, arguments);
    }
}

utils.rewire(some.object, "method", function(){} );

答案 2 :(得分:0)

您可以简单地使用闭包来创建一个通用的钩子函数,它允许您指定在原始函数之前或之后立即调用的另一个函数:

function hookFunction(fn, preFn, postFn) {
    function hook() {
        var retVal;
        if (preFn) {
            preFn.apply(this, arguments);
        }
        retVal = fn.apply(this, arguments);
        if (postFn) {
            postFn.apply(this, arguments);
        } 
        return retVal;
    }
    return hook;
}

因此,对于你想要挂钩的任何函数,你只需调用hookFunction并将它想要挂钩的函数传递给它,然后传递一个可选的pre和post函数或你的函数。 pre和post函数传递与原始函数相同的参数。

所以,如果你原来的功能是这样的:

var fna = function(ar) {
     console.log("argument:",ar);
     return "return value is argument too:"+ar;
}

并且,每次在调用函数之前调用该函数时,您希望发生某些事情,您可以这样做:

fna = hookFunction(fna, function() {
    console.log("Hola, I am some additional stuff being rewired right before");
});

或者如果您希望它在调用原始文件后立即发生,您可以这样做:

fna = hookFunction(fna, null, function() {
    console.log("Hola, I am some additional stuff being rewired right after");
});

工作演示:http://jsfiddle.net/jfriend00/DMgn6/


这可以与对象上的方法以及对象和方法的任意嵌套级别一起使用。

var myObj = function(msg) {
    this.greeting = msg;
};

myObj.prototype = {
    test: function(a) {
        log("myObj.test: " + this.greeting);
    }
}

var x = new myObj("hello");
x.test = hookFunction(x.test, mypreFunc2, myPostFunc2);
x.test("hello");

答案 3 :(得分:0)

基于Claudiu,这似乎是最受欢迎的方式,这里是一个使用for循环并代理上下文的解决方案......但是,我发现这很难看。

var utils = utils || {};
// let's rewire a function. i.e. My.super.method()
utils.rewire = function(method, callback) {
    var obj = window;
    var original = function() {};
    var tree = method.split(".");
    var fun = tree.pop();
    console.log(tree);

    // parse through hierarchy
    for (var i = 0; i < tree.length; i++) {
        obj = obj[tree[i]];
    }

    if(typeof(obj[fun]) === "function") {
        original = obj[fun];
    }
    var cb = callback.bind(obj);
    obj[fun] = function(ar) {
        cb();
        return original.apply(this, arguments);
    }
}

答案 4 :(得分:0)

嗯,这看起来很奇怪。考虑一下这个

function wrap(fn, wrapper) {
    return function() {
        var a = arguments;
        return wrapper(function() { return fn.apply(this, a) })
    }
}

示例:

function foo(a, b) {
    console.log([a, b])
    return a + b
}

bar = wrap(foo, function(original) {
    console.log("hi")
    var ret = original()
    console.log("there")
    return ret
})

console.log(bar(11,22))

结果:

hi
[11, 22]
there
33

将对象方法包装为bind

obj = {
    x: 111,
    foo: function(a, b) {
        console.log([a,b,this.x])
    }
}

bar = wrap(obj.foo.bind(obj), function(fn) {
    console.log("hi")
    return fn()
})