一个JavaScript递归引出的问题

递归引出问题

 最近在看一本JS方面的书,名字叫《JavaScript语言精粹(修订版)》。在看到递归这一节的时候,有一段代码让我想了大概几分钟才想明白是怎么回事,代码如下:

        var haoni = function(disc, src, aux, dst){
            if(disc > 0){
                haoni(disc - 1, src, dst, aux);

                document.writeln('Move disc ' + disc + ' from ' + src + ' to ' + dst + '<br/>');

                haoni(disc -1, aux, src, dst);
            }
        };

        haoni(3, 'Src', 'Aux', 'Dst');
View Code

这是一个有关“汉诺塔”的js实现代码。我主要是看过输出的结果有点不明白。输出如下:

Move disc 1 from Src to Dst
Move disc 2 from Src to Aux
Move disc 1 from Dst to Aux
Move disc 3 from Src to Dst
Move disc 1 from Aux to Src
Move disc 2 from Aux to Dst
Move disc 1 from Src to Dst

或许这样的输出还看不出什么。如果你在每句代码下添加一句打印的代码,结果就很让人迷糊了,如:

        var haoni = function(disc, src, aux, dst){
            document.write('111<br/>');
            if(disc > 0){
                document.write('222<br/>');
                haoni(disc - 1, src, dst, aux);
                document.write('333<br/>');

                document.writeln('Move disc ' + disc + ' from ' + src + ' to ' + dst + '<br/>');

                document.write('444<br/>');
                haoni(disc -1, aux, src, dst);

                document.write('555<br/>');
            }
            document.write('666<br/>  ');
        };

        haoni(3, 'Src', 'Aux', 'Dst');
View Code

结果如下:

111
222
111
222
111
222
111
666
333
Move disc 1 from Src to Dst
444
111
666
555
666
333
Move disc 2 from Src to Aux
444
111
222
111
666
333
Move disc 1 from Dst to Aux
444
111
666
555
666
555
666
333
Move disc 3 from Src to Dst
444
111
222
111
222
111
666
333
Move disc 1 from Aux to Src
444
111
666
555
666
333
Move disc 2 from Aux to Dst
444
111
222
111
666
333
Move disc 1 from Src to Dst
444
111
666
555
666
555
666
555
666
View Code

如果你仔细看下打印的结果,你会发现结果很有意思,这里可以自己发现哦-_-!。

思考问题-查找资料

 细心的人应该会看出上面的疑问。为什么会这样:

666
333   //为什么666之后会是333
Move disc 1 from Src to Dst

这里就要说点其他的了。

JavaScript中有一个重要的东西叫“执行环境”。执行环境定义了变量或者函数有权访问的其他数据,决定了他们各自的行为。而每个执行环境都有一个和他有关的变量对象,环境中定义的所有变量和函数都保存在这个对象中。每个函数都有自己的执行环境。当执行流进入一个函数的时候。函数的执行环境会被推入一个环境栈中。而函数执行之后栈会将他的执行环境弹出,把控制权返回给之前的执行环境。

这段话摘自:《JavaScript高级程序设计》。所以上面的问题就有了解答。

从一个例子解答问题

我们先来看一个小例子:

        (function(num){
            if(num > 1){
                console.log('11');
                arguments.callee(num-1);
                console.log('22');
            }
        }(3));

结果:

11
11
22
22

根据上面资料的介绍,这个结果也就很好理解了。当第一次执行的时候num是3,进入if判断打印‘11’。然后调用自身,这个时候函数(这里叫A)会进入另外一个函数(这里叫B)而新的执行环境也会进来(虽然另外一个函数还是自身)。结果进入到新的函数之后再次if判断,结果符合条件就再次打印‘11’,然后执行环境再次被改变(这里叫C)。在新的执行环境内发现if不在满足,退出当前的执行环境(这里是从C退出),把控制权交给之前的执行环境(这里交给的是B不是A,然后打印‘22‘),而B在这时也不在满足条件就在交给最初的A,然后A继续接下来的执行打印’22‘。

因此

这样上面的结果也就比较好理解了,只是函数里面有两个递归,当第一个递归把控制权交回到最开始的时候是第二个递归的开始,所以就会看到打印的结果跳来跳去,所以使用递归的时候一定要注意。

原文地址:https://www.cnblogs.com/Dn9x/p/3517625.html