JavaScript递归原理

JavaScript递归是除了闭包以外,函数的又一特色呢.很多开发新手都很难理解递归的原理,我在此总结出自己对递归的理解.

所谓递归,可以这样理解,就是一个函数在自身的局部环境里通过自身函数名又调用,如此反复,直到条件不满足,返回最终结果的一种情形.最简单的一个示例代码如下:

function fn(a){
   return a <= 1 ? a = 1 : a * fn(a - 1);
}

这也是一个最经典的递归阶乘函数了,虽然这行代码表面上看起来没什么问题,但在执行如下代码,则会出现错误.

var otherfn = fn;
fn = null;
otherfn(5);//出错,fn is not a function

  

以上将定义的递归阶乘函数fn()保存在变量otherfn中,然后将fn()函数设置为null,也就是说,这样就断掉了对原始函数fn()的引用,因此在调用otherfn()函数时候就会报错.毕竟调用otherfn()实际上就相当于是调用fn()函数,而fn()函数已经被解除了引用,所以自然会报一个fn 不是一个函数的错误呢.

那么,有没有办法解决呢?

JavaScript的arguments.callee就可以解决这个问题.argumens.callee实际上就是指向一个函数的指针,因此,只要将以上代码修改成如下所示:

function fn(a){
   return a <= 1 ? a = 1 : a * arguments.callee(a - 1);
}

这样,通过arguments.callee代替了函数名fn,就保证了引用不会被解除,因此无论怎么调用该函数就不会出问题了.

因此,在编写递归函数时,使用arguments.callee总是比直接用函数名更好一点.

不过,使用arguments.callee有个缺点,那就是在严格模式下,是无非访问arguments.callee的,因此就需要使用命名函数表达式来达到与这个指针带来的效果呢.代码如下:

var fn = (function f(a){
  return a <= 1 ? a = 1 : a * f(a - 1);
});

以上代码创建了一个命名为f的函数表达式,然后将它赋值给一个fn变量.因此即便把这个函数表达式赋值给另一个变量,这个函数也仍然可以正常调用.而且这种做法不仅适合非严格模式,也同样适合严格模式.

原文地址:https://www.cnblogs.com/eveningwater/p/8519669.html

时间: 2024-10-03 22:51:45

JavaScript递归原理的相关文章

JavaScript内部原理实践——真的懂JavaScript吗?(转)

通过翻译了Dmitry A.Soshnikov的关于ECMAScript-262-3 JavaScript内部原理的文章, 从理论角度对JavaScript中部分特性的内部工作机制有了一定的了解.但是,邓爷爷说过:“实践才是检验真理的唯一标准”.所以,我打算通过从内部原理来解释一些经常在笔试或者面试中遇到的关于JavaScript语言层面的题目来进一步学习和掌握JavaScript内部工作原理. 那么,首先就是要去找那些题目,google了一圈终于找到了来自Dmitry Baranovskiy的

How Javascript works (Javascript工作原理) (一) 引擎,运行时,函数调用栈

个人总结: 这篇文章对JS底层的工作原理进行了介绍. 原文:https://blog.sessionstack.com/how-does-javascript-actually-work-part-1-b0bacc073cf 一.引擎,运行时,调用堆栈 这是 JavaScript 工作原理的第一章.本章会对语言引擎,运行时,调用栈做一个概述. 事实上,有很多开发者在每天日常开发中都会使用 JavaScript 但是却不了解其底层的知识. 概述 几乎所有人都已经听说过 V8 引擎的概念,并且很多人

How Javascript works (Javascript工作原理) (五) 深入理解 WebSockets 和带有 SSE 机制的HTTP/2 以及正确的使用姿势

总结: 1.长连接机制--分清Websocket,http2,SSE: HTTP/2 引进了 Server Push 技术用来让服务器主动向客户端缓存发送数据.然而,它并不允许直接向客户端程序本身发送数据.服务端推送只能由浏览器处理而不能够在程序代码中进行处理,意即程序代码没有 API 可以用来获取这些事件的通知. 通过SSE(Server Side Event)来实现服务端向客户端的单向推送,SSE基于HTTP,是单向通信. WebSocket是在服务端和客户端建立双工通信.基于TCP. 这是

How Javascript works (Javascript工作原理) (十一) 渲染引擎及性能优化小技巧

个人总结:读完这篇文章需要20分钟,这篇文章主要讲解了浏览器中引擎的渲染机制. DOMtree       ----|   |---->  RenderTree CSSOMtree  ----| 这是 JavaScript 工作原理的第十一章. 迄今为止,之前的 JavaScript 工作原理系列文章集中于关注 JavaScript 语言本身的功能,在浏览器中的执行情况,如何优化等等. 然而,当在构建网络应用的时候,不仅仅只是编写自己运行的 JavaScript 代码.所编写的 JavaScri

深入理解JavaScript Hijacking原理

最近在整理关于JavaScript代码安全方面的资料,在查关于JavaScript Hijacking的资料时,发现关于它的中文资料很少,故特意整理一下. 一.JavaScript Hijacking原理 其实JavaScript Hijacking和CSRF攻击的思想很类似,关于CSRF攻击可以参考我之前写的<浅谈CSRF攻击方式>,关于JavaScript Hijacking的攻击模型,见下图: (1).你正常访问信任站点(http://www.Bank.com),然后登陆信任站点. (2

JavaScript作用域原理(三)——作用域根据函数划分

一.一个for实例 <p id="scope3" style="color:red"></p> var pscope3 = document.getElementById('scope3'); function scope3() { for(var i=0; i<10; i++){ } echo(pscope3, i); } scope3(); 1.函数在java.C#等语言中,变量i只会在for循环语句中有定义,循环结束,i也就被销毁

JavaScript作用域原理(一)——作用域链

一.作用域的描述 JavaScript权威指南中对作用域有一句很精辟的描述:“JavaScript中的函数运行在它们被定义的作用域里,而不是它们被执行的作用域里.” 在JavaScript中,作用域的概念和其他语言差不多,在每次调用一个函数的时候,就会进入一个函数内的作用域,当从函数返回以后,就返回调用前的作用域. 验证下刚那句权威指南中的话: <p id="scope1" style="color:red"></p> function ec

JavaScript递归中的作用域问题

需求是这样的,从子节点寻找指定className的父节点,一开始就想到递归(笨!),Dom结构如下: <div class="layer_1"> <div class="layer_2"> <div class="layer_3"> <div id="layer_4"></div> </div> </div> </div> 先通过i

JavaScript作用域原理(二)——预编译

JavaScript是一种脚本语言, 它的执行过程, 是一种翻译执行的过程.并且JavaScript是有预编译过程的,在执行每一段脚本代码之前, 都会首先处理var关键字和function定义式(函数定义式和函数表达式). 一.变量执行之前,会被赋为undefined <p id="scope2" style="color:red"></p> function echo(p, html) { p.innerHTML += html + '&l