Javascript 如何有效地确定闭包的深度
在闭包方面,如果只考虑返回另一个函数的函数,如以下示例所示。我们如何在运行时以编程方式确定此闭包的深度 假设此函数的深度为2:Javascript 如何有效地确定闭包的深度,javascript,closures,Javascript,Closures,在闭包方面,如果只考虑返回另一个函数的函数,如以下示例所示。我们如何在运行时以编程方式确定此闭包的深度 假设此函数的深度为2: function F(a){ // 1 return function G(b){ // 2 return 'something'; } } 此函数“H”的深度为3 function H(a){ // 1 return function(b){ //2 return function(c){} //3 } }
function F(a){ // 1
return function G(b){ // 2
return 'something';
}
}
此函数“H”的深度为3
function H(a){ // 1
return function(b){ //2
return function(c){} //3
}
}
到目前为止,我已经编写了一些简单的脚本,通过迭代检查函数的返回类型来确定闭包深度,直到它返回函数以外的其他类型但我的脚本仅在每个嵌套函数不需要参数的情况下工作。请参阅以下代码:
function F(){
return function(){
return function(){
return 1;
}
}
}
function depth(f){
var n = 1;
var ret = f();
while (typeof(ret)=='function'){
ret = ret();
n++;
}
return n;
}
上面的简单函数depth
正确地确定了F
的深度,即3但是,在一些实际情况下,例如闭包将函数作为参数并调用它,我的函数depth
无法处理。
function F2(a,f){
return function(g){
return f(a) + g(a); // This will break my depth function
}
}
*我的问题:有没有办法确定我的收尾深度更有效?特别是在上面提到的某些情况下(闭包将函数作为参数并调用它)。最受欢迎的是能够动态处理闭包的通用方法,闭包可以将某些函数作为参数,也可以不作为参数
p.S.让我把范围缩小如下
- 只考虑纯嵌套函数
- 嵌套函数的每一层总是返回相同的类型
- 函数的深度是恒定的
- 两个嵌套函数都不是递归函数
- 这与其说是答案,不如说是评论,但最好在这里格式化
除非给出一组所有必需的参数,否则这不是一个可解决的问题。
考虑以下计算的“深度”:
function F(a) {
if (a) {
return function G(b) {
return 0;
}
} else {
return 1;
}
}
您可能能够更改所有函数,以便它们也能够在没有参数的情况下运行,以便进行反射?
因为在深度计算过程中,函数调用不应该进行任何其他有用的计算,也不会产生任何副作用。它们应该只返回函数或非函数值。
因为你说:“嵌套函数的每一层总是返回相同的类型。
函数的深度是恒定的。“在遇到空参数列表时返回相应类型的伪响应的决定应该很简单。这里是另一种方法。这通过观察代码的行为在运行时起作用。
我的功能
Reflector
就是这种情况下的特殊调味品。
有关运行示例的详细信息,请参见 该函数
Reflector
执行四项功能:
一,。它通过返回钩子而不是原始函数来“插入”带有钩子(
fh
)的函数。其效果是在调用插入指令的函数之前调用钩子。
二,。调用插入指令的函数时,它将转发调用—它将调用原始函数。并随时准备捕获函数结果。
三,。当函数返回时,它检查结果。如果结果也是一个函数,它将存储新的最大深度。
四,。另外,当返回的结果是一个函数时,钩子也会对返回的函数进行指令插入,以便对新的返回函数再次应用步骤(1)
//Your function You want to USE and REFLECT on too.
function F(){
//return 3;
return function(){
//return 2;
return function(){
return 1;
}
}
}
//Your function You want to USE and REFLECT on too.
function H(a){ // 1
return function(b){ //2
return function(c){ //3
return a + b + c;
}
}
}
//this function is the machinery that knows how to USE the functions You want to measure.
//But this function only USES them, but does no reflection.
function BlackboxF(f) {
var r1 = f();
if (typeof r1 == "function")
{
var r2 = r1();
if (typeof r2 == "function")
{
var r3 = r2();
return r3;
}
else
{
return r2;
}
}
else
{
return r1;
}
}
//this function is the machinery that knows how to USE the functions You want to measure.
//But this function only USES them, but does no reflection.
function BlackboxH(f) {
var r1 = f(1);
var r2 = r1(2);
var r3 = r2(4);
return r3;
}
var maxdepth = 1;
//This is the special agent for reflecting code as it runs
function Reflector(f, depth) {
if (!depth)
depth = 1;
//1. It "instruments" a function with a hook (`fh`) by returning the hook
//instead of the original function. The effect is that the hook is called
//before that instrumented function is called.
var fh = function()
{
//2. When the instrumented function is called, it forwards the call - it calls
//the original function. And remains ready for capturing the function result.
var r = f.apply(this, arguments);
//3. When the function returns, it inspects the result.
//If the result is also a function, it stores new maximum depth.
if (typeof r == "function")
{
maxdepth = Math.max(maxdepth, depth + 1);
//4. Also, when the returned result was a function, the hook also
//instruments the returned function, so that step (1) is again applied
//for the new returned function.
return Reflector(r, depth + 1);
}
else
{
return r;
}
};
return fh;
}
if (false) //The simple case with no arguments
{
var F2 = Reflector(F);
var RF = BlackboxF(F2);
document.getElementById("result").textContent = "Result: " + RF;
document.getElementById("depth").textContent = "Depth: " + maxdepth;
}
else //A more complicated case with arguments
{
var H2 = Reflector(H);
var RH = BlackboxH(H2);
document.getElementById("result").textContent = "Result: " + RH;
document.getElementById("depth").textContent = "Depth: " + maxdepth;
}
OP在10万年前才将此类案例排除在他的问题之外:-)@Bergi并非所有人都在阅读问题的更新版本,但感谢您的注释。正如在对问题的答复中所讨论的那样,这个案例使事情变得更加复杂。所以我决定退出这个案例。当然,根据OP对“同一类型”的精确定义,
else{return function H(b){return function J(c){return 1;}}}
的更新很可能不会被排除在外@ScottSauyet-Hmm,这是一个有点棘手的问题。然而,用常规方法可能很难解决可变深度问题。你的意思是通过移除函数体来更改每一层函数吗?我不太确定如何实际实现这一点,也许是通过猴子补丁?不知道如何在不使用maki的情况下通过编程方式更改函数正在取消对其(嵌套)的任何更改返回值。@TaoP.R。我的意思是在函数头代码中添加几行代码,而不是删除函数体或更改其定义的功能。如果您想要编程解决方案,请参阅我的第二个答案。您的反射器方法对我来说很有意思。但是,它看起来比我预期的要复杂一些。您可以吗解释你是如何设计的?@TaoP.R.我在我的回答文本中添加了关于Reflector
工作原理的解释,并将解释也插入到代码中。现在是更清楚了还是你想澄清一些东西?此外,如果你想,这种方法可以进一步升级,以便它能够反映多个“根”函数(F
和H
)同时执行,并分别报告每个函数的深度。我现在没有添加这样的代码,因为这样答案会太长。但如果有必要,我可以添加关于观察多个“根”所需方法的一般说明并发函数。因此,最重要的因素是“我们需要知道如何将适当的参数传递给每个函数”。此反射器似乎在一般情况下运行良好。@TaoP.R.如果您愿意将参数类型预定义为基本类型(例如,数字),并且允许对所有这些参数使用一些基值(例如,零),然后有一个技巧可以绕过对知道如何使用函数的机器的需求,并自动生成调用。实际上,对基本类型的需求并不严格——只是很可能,但允许使用一些公共基值的需求是必要的。我想你的方法可能会给我一些想法。我将尝试扩展我只需要一个通用的方法,我们不需要知道如何调用bef