JavaScript(第五天)—爱创课堂专业前端培训
一、递归函数
函数内部调用函数本身;
如果函数一直自己调用自己,那么就成了死循环。程序就会造成内存堆栈溢出,终止程序;
所以,递归函数一定要给一个条件,来跳出函数。
递归一般用来解决数学问题;
一般是大于0的自然数的处理!!!
如:求阶乘 5!=5*4*3*2*1
// fn();// function fn() {// fn();// }//Uncaught RangeError: Maximum call stack size exceeded//求阶乘 5!=5*4*3*2*1console.log(jieCheng(5));//累乘法// function jieCheng(num) {// var result = 1;// for (var i = 5; i > 0; i--) {// result *= i;// }// return result;// }//递归函数法function jieCheng(n) { if(n === 1){ return 1; } return n * jieCheng(n-1);}/** 函数调用,传参5* 返回:5 * jieCheng(5-1) = 5 * 4 * jieCheng(4-1) = 5 * 4 * 3 * jieCheng(3-1)* = 5 * 4 * 3 * 2 * jieCheng(2-1)* = 5 * 4 * 3 * 2 * 1* = 120* */
1
求斐波那契数列 1,1,2,3,5,8,13,21,34,55……,求第N项是多少
console.log(feiBo(5));console.log(feiBo(6));console.log(feiBo(7));console.log(feiBo(8));console.log(feiBo(9));console.log(feiBo(10));console.log(feiBo(11));function feiBo(n) { if(n === 1 || n === 2){ return 1; } return feiBo(n-1)+feiBo(n-2);}/** feiBo(n) = feiBo(5) = feiBo(5-1) + feBo(5-2) = feiBo(4) + feiBo(3)* = (feiBo(4-1) + FeiBo(4-2)) + (feiBo(3-1) + feiBo(3-2))* = (feiBo(3) + feiBo(2)) + ( feiBo(2)+feiBo(1))* = feiBo(3) + 2 * feiBo(2) + feiBo(1)* = (feiBo(3-1) + feiBo(3-2)) + 2 * 1 + 1* = feiBo(2) + feiBo(1) + 2 + 1* = 1 + 1 + 2 + 1* = 5* */
1
二、立即执行函数与匿名函数
立即执行函数:也叫自执行函数,IIFE函数;程序运行,函数即可自动执行;由效果对函数体进行包裹,后面一对小括号执行函数。
匿名函数:没有名字的函数
1
2 (function(形参){
//函数体
3 })(实参);
(function (a,b) { console.log(a+b);})(10,20);
1
注:一般自执行函数用于加载页面时,只执行一次的操作
补充:函数体除了可以使用小括号进行包裹,还可以在函数体前面加 ~! + -
(function (a,b) { console.log(a+b);})(10,20);~function (a,b) { console.log(a+b);}(10,20);!function (a,b) { console.log(a+b);}(10,20);-function (a,b) { console.log(a+b);}(10,20);+function (a,b) { console.log(a+b);}(10,20);
1
三、闭包函数
概念:一个函数可以调用另外一个函数内部的变量
提取关键字:
两个函数
局部作用域
局部变量只能在变量当前作用域内被调用,作用域外部是没有办法调用到这个变量。
那么想要访问一个函数内部的变量,就需要从这个函数内部声明一个子函数,那么这个子函数就可以任意的调用父函数中的变量了。反之,父函数却不能调用子函数中的变量。这就是js中存在的链式作用域的概念。
var str = "Hello World!!";console.log(fn());//ƒ fn2() {console.log("num:",num);}console.log("num:",fn()());//num: 10function fn() { var num = 10; // console.log("num:",num); function fn2() { // console.log("num:",num); return num; } return fn2;}// console.log("num:",num);// num is not defined
1
但是,这种fn2形成的闭包函数,并不是我们所要说的。我们想要的是函数外部的函数可以调用这个函数内部的局部变量。
思考?可不可以将内部的函数作为一个桥梁,来连接内外 ,作为一个传递数据的通道
function fn() { var num = 10; return function () { return num; }}console.log("fn函数:",fn());console.log("fn内部匿名函数执行结果:",fn()());//现在想要在fn函数的外部调用fn内部的变量num,该怎么做???var test = fn();//test 和 内部的匿名函数一样,形成一个闭包;都叫做闭包函数console.log("test函数:",test);console.log("test函数执行结果:",test());
1
闭包函数的特点:
观察下面代码,内部匿名函数,每一次执行,都是一次全新的开始,会形成一个新的闭包;
但是用外部变量test或test2来声明接收的fn内部匿名函数的赋值,test或test2函数会形成自己的闭包;
由于fn内部匿名函数和变量是局部的,单独执行调用时生成,调用完毕结束;
但是test或test2不同,它是一个全局变量(函数),全局就是页面生成时创建,关闭销毁;常驻内存了。
以test为例,从内存角度来讲,与fn内部的匿名函数建立了一个引用关系,而这个匿名函数又和fn内部的变量num有引用关系;在js中,有一个垃圾回收机制,只有当对象之间不存在引用关系时,才会回收。所以,test去调用的num并没有被回收,而是常驻内存,所以在我们连续执行几次test之后,num依次递增。
function fn() { var num = 10; return function () { return num++; }}
// console.log("fn函数:",fn());// console.log("fn内部匿名函数执行结果:",fn()());//现在想要在fn函数的外部调用fn内部的变量num,该怎么做???var test = fn();var test2 = fn();// console.log("test函数:",test);// console.log("test函数执行结果:",test());console.group("fn内部的函数连续执行4次");console.log("fn内部的函数第1次执行",fn()());//10console.log("fn内部的函数第2次执行",fn()());//10console.log("fn内部的函数第3次执行",fn()());//10console.log("fn内部的函数第4次执行",fn()());//10console.log("fn内部的函数每一次执行都会形成一个新的闭包")console.groupEnd();console.group("test函数连续执行4次");console.log("test函数第1次执行:",test());//10console.log("test函数第2次执行:",test());//11console.log("test函数第3次执行:",test());//12console.log("test函数第4次执行:",test());//13console.groupEnd();console.log(test2());//10console.log(test2());//11
1
闭包函数使用过多:可能会造成内存泄漏的问题,以及对全局变量造成污染。
但是在很多高级程序开发过程中,也会经常用到闭包,闭包是一个重点也是一个难点。
闭包的应用:
在循环中的应用:定时器和事件函数
求fn(3)(4)(5)(6),结果是 360
// 求fn(3)(4)(5)(6),结果是 360console.log(fn(3)(4)(5)(6));function fn(num1) { return function (num2) { return function (num3) { return function (num4) { return num1 * num2 * num3 * num4; } } }}
1
关注VX公众号“icketang” 免费领取华为荣耀商城项目实战视频教程