JS函数-我调用自己试试看
前言
最近在读《JavaScript语言精粹》,对递归函数有了进一步的认识,希望总结下来:
递归是一种强大的编程技术,他把一个问题分解为一组相似的子问题,每一问题都用一个寻常解去解决。递归函数就是会直接或者间接调用自身的一种函数,一般来说,一个递归函数调用自身去解决它的子问题。
"汉诺塔"经典递归问题
"汉诺塔"是印度的一个古老传说,也是程序设计中的经典的递归问题,是一个著名的益智游戏:
题目如下:
塔上有三根柱子和一套直径各不相同的空心圆盘,开始时源柱子上的所有圆盘都按从大到小的顺序排列。目标是通过每一次移动一个圆盘到另一根柱子上,最终把一堆圆盘移动到目标柱子上,过程中不允许把较大的圆盘放置在较小的圆盘上;

寻找规律(把所有的圆盘移动到C):
1)n(圆盘个数) == 1
第一次:1号盘 A -> C sum(移动次数) = 1
2)n == 2
第一次:1号盘 A -> B
第二次:2号盘 A -> C
第三次:1号盘 B -> C sum = 3
3)n == 3
第一次:1号盘 A -> C
第二次:2号盘 A -> B
第三次:1号盘 C -> B
第四次:3号盘 A -> C
第五次:1号盘 B -> A
第六次:2号盘 B -> C
第七次:1号盘 A -> C sum = 7
以此类推...
故不难发现规律,移动次数为:sum = 2^n - 1
算法分析(递归):
把一堆圆盘从一个柱子移动另一根柱子,必要时使用辅助的柱子。可以把它分为三个子问题:
首先,移动一对圆盘中较小的圆盘到辅助柱子上,从而露出下面较大的圆盘,
其次,移动下面的圆盘到目标柱子上
最后,将刚才较小的圆盘从辅助柱子上在移动到目标柱子上
把三个步骤转化为简单数学问题:
(1) 把 n-1个盘子由A 移到 B;
(2) 把 第 n个盘子由 A移到 C;
(3) 把n-1个盘子由B 移到 C;
我们创建一个JS函数,当它调用自身的时候,它去处理当前正在处理圆盘之上的圆盘。最后它回一个不存在圆盘去调用,在这种情况下,它不在执行任何操作。
JavaScript源代码实现
var hanoi = function(disc,src,aux,dst){
if(disc>0){
hanoi(disc-1,src,dst,aux);
console.log(' 移动 '+ disc + ' 号圆盘 ' + ' 从 ' + src + ' 移动到 ' + dst);
hanoi(disc-1,aux,src,dst)
}
}
hanoi(3,'A','B','C')

整个算法的思路是:
- 将A柱子上的n-1个盘子暂时移到B柱子上
- A柱子只剩下最大的盘子,把它移到目标柱子C上
- 最后再将B柱子上的n-1个盘子移到目标柱子C上

JS递归函数遍历Dom
递归函数可以非常高效的操作树形结构,在JavaScript有一种"天然的树形结构"浏览器端的文档对象模型(Dom)。每次递归调用时处理指定树的一小段。
/* 我们定义一个walk_the_DOM函数,
1) 它从某个指定的节点开始,按指定HTML源码的顺序,访问树的每个节点
2)它会调用一个函数,并依次传递每个节点给它,walk_the_DOM调用自身去处理每一个节点
*/
var walk_the_DOM = function walk( node , func ) {
func(node);
node = node.firstChild;
while (node) {
walk( node , func );
node = node.nextSibling;
}
} /* 在定义一个getElementByAttribute函数
1) 它以一个属性名称字符串和一个可选的匹配值作为参数
2) 它调用walk_the_DOM,传递一个用来查找节点属性名的函数作为参数,匹配得节点都会累加到一个数组中
*/ var getElementsByAttribute=function(att,value){
var results=[];
walk_the_DOM(document.body,function(node){
var actual=node.nodeType===1&&node.getAttribute(att);
if(typeof actual==='string' &&( actual===value|| typeof value!=='string')){
results.push(node);
}
});
return results;
}
命名函数表达式和递归
递归问题
求阶乘的函数:
function factorial(num){
if(num<=1){
return 1;
}else{
return num*factorial(num-1);
}
}
通过将函数factorial设置为null,使原始函数的引用只剩一个, 此时factorial已不再是函数

arguments.callee实现递归
arguments.callee是一个指向正在执行的函数的指针,因此可以用它来实现对函数的递归调用
function factorial(num){
if(num<=1){
return 1;
}else{
return num*arguments.callee(num-1);
}
}
var anotherFactorial=factorial;
factorial=null;
anotherFactorial(3) //
用arguments.callee代替函数名,可以确保无论怎样调用函数都不会出问题。因此,在编写递归函数时,使用arguments.callee总比使用函数名更保险。
但是在严格模式下,不能通过脚本访问arguments.callee,访问这个属性会报错

命名函数表达式实现递归
创建一个名为f()的命名函数表达式,然后赋值给factorial,即使把函数赋值给了另一个变量,函数的名字f仍然有效,所以递归调用照样能正常完成。
这种方式在严格模式和非严格模式都可行。
var factorial =function f(num){
'use strict'
if(num<=1){
return 1;
}else{
return num* f (num-1);
}
}
factorial(3) //
var anotherFactorial=factorial;
factorial=null;
anotherFactorial(3) //
写在后面
何不在别人去"坚持"的时间,试着让自己去爱...因为喜爱,所以我们付出,但正是因为付出了,所以我们只能更爱.
大学生一枚才疏学浅,如有纰漏,还望前辈指正。
JS函数-我调用自己试试看的更多相关文章
- js函数的调用问题
1.js函数的调用方式有三种.请问以下“二”处的几行代码有什么猫腻? //一 事件调用 btn.onclick=fn; //二 直接调用(window调用) fn(); //自上而下解析到这一行的时候 ...
- flash、js 函数 互相调用
js调用flex函数 flex 利用ExternalInterface.addCallback(“注册的方法名”,As中的函数名)进行注册 js中,用document.getElementById(“ ...
- js 函数的调用模式
1.函数调用 调用一个函数将暂停当前函数的执行,传递控制权和参数给新函数.除了函数声明时定义的形参,每个函数还接受两个附加的参数:this和arguments(arguments并不是一个真正的数组, ...
- js函数简单调用
<script> //最简单的调用 //这是JavaScript DOM编程艺术(第2版)关于函数的原码 function convertToCelsius(temp) { var res ...
- VC与JavaScript交互(二) --- 调用JS函数
这一章,我们来动手实践VC调用JS函数. 我们动手写一个HTML,其中包含这样一段JS代码: //[html] <script type="text/javascript"& ...
- js函数、表单验证
惊天bug!!!在script里面只要有一点点错误,就都不执行了!!!所以每写一个方法,就跑一下,因为这个书写疏忽导致的bug不可估量!!! [笑哭,所以我才这么讨厌js么,后来真心的是一点都不想再看 ...
- Js函数的概念、作用、创建、调用!
一.函数是用来帮助我们封装.调用代码的最方便的工具! 二.函数的创建方法有三种: 三.函数的创建方式有3种,调用方式也不是单一的,调用方式有4种! 1.作为一个函数去调用 函数名+();(函 ...
- JS中函数的调用和this的值
调用每一个函数会暂停当前函数的执行,传递控制权和参数给新函数.除了声明时定义的形式参数,每个函数还接收两个附加的参数:this 和 arguments. 参数this在面向对象编程中非常重要,他的值取 ...
- AS与JS相互通信(Flex中调用js函数)
转载自http://www.blogjava.net/Alpha/archive/2009/06/27/284373.html Flex中As调用Js的方法是: 1.导入包 (import f ...
随机推荐
- CentOS-7.2添加桌面快捷方式
一,在桌面新建一个文件 文件名随意,但必须带有.desktop的后缀名. gedit /home/zgw/Desktop/zgw.desktop 二,在文件中写入如下内容 [Desktop Entry ...
- FZU 2253 salty fish
https://vjudge.net/problem/FZU-2253 题意:略 思路: 一开始改变区间,还以为是线段树...还是dp的题做得太少了. 这题一开始我们可以统计出一共有多少只翻身的咸鱼, ...
- RabbitMq学习一入门篇(hello world)
简介 RabbitMQ是一个开源的AMQP实现,服务器端用Erlang语言编写,支持多种客户端,如:Python.Ruby..NET.Java,也是众多消息队列中表现不俗的一员,作用就是提高系统的并发 ...
- VSCode自定义配色方案
说明 本文更新于2017-07-24,使用VSCode 1.14.1,操作系统为Windows. 配置文件 "文件-首选项-颜色主题"即可显示所有可用的颜色主题,上下选择后Ente ...
- KMP算法 --- 在文本中寻找目标字符串
KMP算法 --- 在文本中寻找目标字符串 很多时候,为了在大文本中寻找到自己需要的内容,往往需要搜索关键字.这其中就牵涉到字符串匹配的算法,通过接受文本和关键词参数来返回关键词在文本出现的位置.一般 ...
- 聊聊synchronized的锁问题
本文不会特别深入细致地讨论synchronized,只是做一个通俗易懂的说明,以及看清一类问题的本质,希望能给大家一点启发. 问题描述 有一个类A,提供了三个方法.分别是静态同步方法,非静态同步方法, ...
- 表达式求值(栈方法/C++语言描述)(一)
一个算数表达式(以下简称为表达式)由运算数.运算符.左括号和右括号组成,定义一个枚举类型TokenType表示为: typedef enum { BEGIN, NUMBER, OPERATOR, LE ...
- Zabbix监控nginx性能
编辑nginx的配置文件nging #配置ngx_status location /nginx_status{ stub_status on; access_log off; } #重启nginx # ...
- [BZOJ3038]上帝造题的七分钟2 树状数组+并查集
考试的时候用了两个树状数组去优化,暴力修改,树状数组维护修改后区间差值还有最终求和,最后骗了40分.. 这道题有好多种做法,求和好说,最主要的是开方.这道题过的关键就是掌握一点:在数据范围内,最多开方 ...
- python实战===输入密码以******的形式在cmd中展示
#设置密码输入,显示为****** import msvcrt,sys def pwd_input(): chars = [] while True: try: newChar = msvcrt.ge ...