我可以覆盖Function对象的行为,以便我可以在每个函数调用之前注入行为,然后继续正常吗?具体来说,(虽然一般的想法本身很有趣)我可以在每个函数调用时登录到控制台而无需在任何地方插入console.log语句吗?那么正常的行为还在继续吗?
我确实认识到这可能会产生严重的性能问题; 即使在我的开发环境中,我也无意进行此操作.但如果它工作,似乎是一个优雅的解决方案,以获得运行代码1000米的视图.我怀疑答案将向我展示更深入的javascript.
etl*_*ett 22
显而易见的答案如下:
var origCall = Function.prototype.call;
Function.prototype.call = function (thisArg) {
console.log("calling a function");
var args = Array.prototype.slice.call(arguments, 1);
origCall.apply(thisArg, args);
};
Run Code Online (Sandbox Code Playgroud)
但这实际上立即进入一个无限循环,因为调用的行为console.log
执行一个函数调用,该函数调用执行函数调用,调用console.log
函数调用,console.log
...
重点是,我不确定这是可能的.
Ken*_*nny 15
许多人试图覆盖.call.有些人失败了,有些人成功了.我正在回答这个老问题,因为它已在我的工作场所提出,这篇文章被用作参考.
我们只能修改两个与函数调用相关的函数:.call和.apply.我将演示两者的成功覆盖.
TL; DR:OP提出的问题是不可能的.答案中的一些成功报告是由于控制台在评估之前在内部调用.call,而不是因为我们想要拦截的调用.
这似乎是人们提出的第一个想法.有些比其他更成功,但这是一个有效的实现:
// Store the original
var origCall = Function.prototype.call;
Function.prototype.call = function () {
// If console.log is allowed to stringify by itself, it will
// call .call 9 gajillion times. Therefore, lets do it by ourselves.
console.log("Calling",
Function.prototype.toString.apply(this, []),
"with:",
Array.prototype.slice.apply(arguments, [1]).toString()
);
// A trace, for fun
console.trace.apply(console, []);
// The call. Apply is the only way we can pass all arguments, so don't touch that!
origCall.apply(this, arguments);
};
Run Code Online (Sandbox Code Playgroud)
这成功拦截了Function.prototype.call
让它旋转一下,好吗?
// Some tests
console.log("1"); // Does not show up
console.log.apply(console,["2"]); // Does not show up
console.log.call(console, "3"); // BINGO!
Run Code Online (Sandbox Code Playgroud)
重要的是,这不是从控制台运行.各种浏览器有各种控制台工具调用.CALL自己有很多,其中包括一次对于每个输入,这可能会混淆在当下的用户.另一个错误是只有console.log参数,它通过控制台api进行字符串化,从而导致无限循环.
那么,申请呢?它们是我们唯一的魔术召唤功能,所以我们也尝试一下.这里有一个兼具两者的版本:
// Store apply and call
var origApply = Function.prototype.apply;
var origCall = Function.prototype.call;
// We need to be able to apply the original functions, so we need
// to restore the apply locally on both, including the apply itself.
origApply.apply = origApply;
origCall.apply = origApply;
// Some utility functions we want to work
Function.prototype.toString.apply = origApply;
Array.prototype.slice.apply = origApply;
console.trace.apply = origApply;
function logCall(t, a) {
// If console.log is allowed to stringify by itself, it will
// call .call 9 gajillion times. Therefore, do it ourselves.
console.log("Calling",
Function.prototype.toString.apply(t, []),
"with:",
Array.prototype.slice.apply(a, [1]).toString()
);
console.trace.apply(console, []);
}
Function.prototype.call = function () {
logCall(this, arguments);
origCall.apply(this, arguments);
};
Function.prototype.apply = function () {
logCall(this, arguments);
origApply.apply(this, arguments);
}
Run Code Online (Sandbox Code Playgroud)
......让我们试一试!
// Some tests
console.log("1"); // Passes by unseen
console.log.apply(console,["2"]); // Caught
console.log.call(console, "3"); // Caught
Run Code Online (Sandbox Code Playgroud)
如您所见,调用括号不会被注意到.
幸运的是,调用括号不能从JavaScript中截取.但即使.call会拦截函数对象上的括号运算符,我们如何调用原始函数而不会导致无限循环?
重写.call/.apply唯一的做法是拦截对这些原型函数的显式调用.如果控制台与该黑客一起使用,则会有大量垃圾邮件.如果使用它,还必须非常小心,因为使用控制台API会很快导致无限循环(如果给一个非字符串,console.log将在内部使用.call).
归档时间: |
|
查看次数: |
22032 次 |
最近记录: |