假设我有一个名为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()
方法。
额外奖励问题:有更清洁的方法吗?开箱即用的简洁和神奇的图书馆?
答案 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()
})