gpt4 book ai didi

javascript - 扩展 native 函数以在函数调用时运行代码

转载 作者:行者123 更新时间:2023-11-29 19:49:20 26 4
gpt4 key购买 nike

  • 是否有原型(prototype)或扩展 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;
};

当然这段代码不起作用,但这里的目标是对函数调用执行时间进行基准测试。

我知道我可以在函数本身之外执行此操作并且不扩展 native Function 对象(这通常是一个坏主意)但这实际上只是一个实验而不是一个严肃的解决方案。

我想对多个函数进行基准测试,因此这将是一个不那么乏味的解决方案。

这也是我不为 callapply 属性制作原型(prototype)的原因(这意味着我必须重写每个函数调用 test ()test.call())。

提前致谢!

最佳答案

不可能有效地拦截 JavaScript 中的所有方法调用。您始终可以覆盖 Function.prototype.callFunction.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 在评论中所说的话。

If you want to profile all functions instead of just a few selected ones, you're better off using your browser's developer tools instead of some script.

关于javascript - 扩展 native 函数以在函数调用时运行代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18253095/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com