扩展本机函数以在函数调用时运行代码
Extend native Function to run code on function call
- 是否有任何方法可以在JavaScript中原型或扩展本机
Function
对象,以便在函数调用中运行另一个函数
Function.prototype.called = function() { var start = new Date().getTime(); var returnValue = this(); this.end = new Date().getTime() - start; this.calls += 1; return returnValue; };
当然,这段代码不起作用,但这里的目标是对函数调用执行时间进行基准测试。
我知道我可以在函数本身之外通过不扩展本机Function
对象来实现这一点(这通常是个坏主意),但这实际上只是一个实验,而不是一个严肃的解决方案。
我想对多个函数进行基准测试,这样这将是一个不那么乏味的解决方案。
这也是我不原型化call
和apply
属性的原因(这意味着我必须将每个函数调用test()
重写为test.call()
)。
提前谢谢!
不可能有效地拦截JavaScript中的所有方法调用。您可以始终覆盖Function.prototype.call
和Function.prototype.apply
,但在正常调用函数时不会调用它们,例如someFunction();
。
然而,如果您的目标是来自特定对象的方法,那么您可以始终对这些对象进行深度遍历,并将每个函数封装到一个拦截器函数中。但是,请注意,对于在进程运行后添加的每个方法,都必须重新运行该拦截进程。
我为您创建了一个示例:
/**
* AOP utility function developed for learning purposes.
*
* @param {Object} o The object to traverse for overriding functions.
* @param {RegExp} rx A regular expression for matching members.
* @param {String} pointcut 'before' or 'after'.
* @param {Function} advice The function to run when the pointcut is met. This function will be passed an {Options} object as last argument.
* @param {maxDepth} maxDepth The maximum depth for deep-traversal. Defaults to 0.
*
* Options object
* overrideReturn {Boolean} - True to override the return value of the original function with the return value of the advice. Defaults to false. Pointcuts: before, after
* cancel {Boolean} - True to avoid calling the original function. Default to false. Pointcuts: before
* overrideArgs {Boolean} - True to override the arguments that will be passed to the original function with the result of the advice. Defaults to false. Pointcuts: before
* result {*} - The return value of the original function. Pointcuts: after
*/
function inject(o, rx, pointcut, advice, maxDepth) {
var pointcuts = {
before: function (fn1, fn2) {
return function () {
var options = injectNewOptions(arguments, BeforeOptions),
fn2Result = fn2.apply(this, arguments),
fn1Result;
if (options.cancel) {
return fn2Result;
}
fn1Result = fn1.apply(this, (options.overrideArgs ? fn2Result : arguments));
return options.overrideReturn ? fn2Result : fn1Result;
};
},
after: function (fn1, fn2) {
return function () {
var fn1Result = fn1.apply(this, arguments),
options = injectNewOptions(arguments, Options),
fn2Result;
options.result = fn1Result;
fn2Result = fn2.apply(this, arguments);
return options.overrideReturn ? fn2Result : fn1Result;
};
}
},
Options = {
overrideReturn: false
},
BeforeOptions = Object.create(Options, {
cancel: {
enumerable: true,
writable: true,
value: false
},
overrideArgs: {
enumerable: true,
writable: true,
value: false
}
});
function injectNewOptions(args, baseOptions) {
var options = Object.create(baseOptions);
Array.prototype.push.call(args, options);
return options;
}
inject = function (o, rx, pointcut, advice, maxDepth, depth) {
var k, f;
maxDepth = maxDepth || 0;
depth = 0 || depth;
for (k in o) {
if (typeof (f = o[k]) === 'function' && rx.test(k)) {
o[k] = pointcuts[pointcut](f, advice, pointcut);
} else if (typeof f === 'object' && maxDepth <= depth) {
inject(f, rx, pointcut, advice, maxDepth, ++depth);
}
}
};
inject.apply(this, arguments);
}
现在我们可以像一样使用inject
var o = {
sum: function (a, b) {
return a + b;
},
product: function (a, b) {
return a * b;
}
};
inject(o, /^sum$/, 'before', function () {
var options = arguments[arguments.length - 1]; //get options object
//override the arguments passed to the intercepted method
options.overrideArgs = true;
return [2, 2];
});
inject(o, /^product$/, 'after', function () {
var options = arguments[arguments.length - 1]; //get options object
//override the arguments passed to the intercepted method
options.overrideReturn = true;
return options.result + 3;
});
o.sum(1, 2); //4 because we have overriden the args with [2, 2]
o.product(2, 2); //7 because we added 3 to the result and overrided the return value
编辑:
这里值得一提的是@Bergi在评论中所说的话。
如果您想评测所有函数,而不是只评测选定的几个函数当然,你最好使用浏览器的开发工具一些脚本。
相关文章:
- AJAX调用运行C代码的最佳实践
- 在经过一段时间或满足条件后运行代码
- 在Firefox restartless插件中,当一个新窗口打开时,我如何运行代码(监听窗口打开)
- 如果调试器关闭,Internet Explorer将出现运行代码问题
- JQuery 帖子未在 PHP 文件中运行代码
- 当ajax请求发生时运行代码的Chrome扩展
- 当我运行代码时,我得到以下结果 []对象对象] [对象对象],但应该给我一个有序数组
- 仅当客户端连接到Meteor服务器时才运行代码
- 在.each()循环中的ajax完成后,Jquery运行代码
- node.js和Cygein,我该如何运行代码
- 未访问全局变量,未运行代码
- Meteor - 在客户端上的异步回调的 for 循环后运行代码
- 运行代码以在Android应用程序中单击javascript按钮?尝试在页面上抓取回复按钮联系信息 craigslist
- 函数结束时如何运行代码
- JS 在不满足条件时在 if 语句中运行代码段
- 在 Ember 视图参数更改上运行代码
- 如何在 YUI 模块中运行代码
- 如何在未在 iframe 中定义的 iFrame 中运行代码
- 在后台运行代码,同时显示警报
- 加载页面时运行代码