如何有效地确定封闭的深度

时间:2015-06-09 18:14:33

标签: javascript closures

就闭包而言,如果仅考虑返回另一个函数的函数,如以下示例所示。我们如何在运行时以编程方式确定此闭包的深度

让我们说这个函数F的深度为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(){
    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。 让我缩小范围如下。

  • 仅考虑纯嵌套函数。
  • 嵌套函数的每一层始终返回相同的类型。
  • 功能的深度是恒定的。
  • 其中一个嵌套函数都不是递归函数。

3 个答案:

答案 0 :(得分:1)

这更多是评论而不是答案,但最好在此格式化。

除非您提供一组所有必需参数,否则这不是一个可解决的问题 考虑计算以下内容的"深度"

[row,col]

答案 1 :(得分:1)

您可能能够更改所有功能,以便它们能够在没有参数的情况下运行,以实现您的反思目的吗?
因为在深度计算期间,函数调用不应该进行任何其他有用的计算或者无论如何都有任何副作用。它们应该只返回一个函数或一个非函数值。
因为你说:“嵌套函数的每一层总是返回相同的类型。 函数的深度是不变的。“在遇到空参数列表时返回相应类型的虚拟响应的决定应该是简单的。

答案 2 :(得分:1)

这是另一种方法。这在运行时通过观察代码的行为来工作。 我的功能Reflector是这种情况下的特殊酱。
有关运行示例的信息,请参阅https://jsfiddle.net/rffv34oz/8/

函数Reflector做了四件事:
1。它通过返回钩子而不是原始函数来“检测”具有钩子(fh)的函数。结果是在调用检测函数之前调用了钩子。
2。当调用检测函数时,它转发调用 - 它调用原始函数。并准备好捕获功能结果。
3。当函数返回时,它会检查结果。如果结果也是函数,则存储新的最大深度。
4。此外,当返回的结果是函数时,钩子也会检测返回的函数,以便再次对新返回的函数应用步骤(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;
}