技术文章 | Technical articles

JavaScript(第五天)—web前端培训

一、递归函数

函数内部调用函数本身;

如果函数一直自己调用自己,那么就成了死循环。程序就会造成内存堆栈溢出,终止程序;

所以,递归函数一定要给一个条件,来跳出函数。

递归一般用来解决数学问题;

一般是大于0的自然数的处理!!!

如:求阶乘 5!=5*4*3*2*1


// fn();
// function fn() {
//     fn();
// }
//Uncaught RangeError: Maximum call stack size exceeded

//求阶乘 5!=5*4*3*2*1
console.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,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
* */

 

二、立即执行函数与匿名函数

立即执行函数:也叫自执行函数,IIFE函数;程序运行,函数即可自动执行;由效果对函数体进行包裹,后面一对小括号执行函数。

匿名函数:没有名字的函数

(function(形参){

    //函数体

})(实参);


 

(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);

+function (a,b) {
    console.log(a+b);
}(10,20);

 

三、闭包函数

概念:一个函数可以调用另外一个函数内部的变量

提取关键字:

两个函数

局部作用域

局部变量只能在变量当前作用域内被调用,作用域外部是没有办法调用到这个变量。

那么想要访问一个函数内部的变量,就需要从这个函数内部声明一个子函数,那么这个子函数就可以任意的调用父函数中的变量了。反之,父函数却不能调用子函数中的变量。这就是js中存在的链式作用域的概念。

var str = "Hello World!!";
console.log(fn());//ƒ fn2() {console.log("num:",num);}
console.log("num:",fn()());//num: 10
function 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

 

但是,这种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());

 

闭包函数的特点:

观察下面代码,内部匿名函数,每一次执行,都是一次全新的开始,会形成一个新的闭包;

但是用外部变量testtest2来声明接收的fn内部匿名函数的赋值,testtest2函数会形成自己的闭包;

由于fn内部匿名函数和变量是局部的,单独执行调用时生成,调用完毕结束;

但是testtest2不同,它是一个全局变量(函数),全局就是页面生成时创建,关闭销毁;常驻内存了。

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()());//10
console.log("fn内部的函数第2次执行",fn()());//10
console.log("fn内部的函数第3次执行",fn()());//10
console.log("fn内部的函数第4次执行",fn()());//10
console.log("fn内部的函数每一次执行都会形成一个新的闭包")
console.groupEnd();

console.group("test函数连续执行4次");
console.log("test函数第1次执行:",test());//10
console.log("test函数第2次执行:",test());//11
console.log("test函数第3次执行:",test());//12
console.log("test函数第4次执行:",test());//13
console.groupEnd();

console.log(test2());//10
console.log(test2());//11

闭包函数使用过多:可能会造成内存泄漏的问题,以及对全局变量造成污染。

但是在很多高级程序开发过程中,也会经常用到闭包,闭包是一个重点也是一个难点。

闭包的应用:

在循环中的应用:定时器和事件函数

fn(3)(4)(5)(6),结果是 360

// 求fn(3)(4)(5)(6),结果是 360
console.log(fn(3)(4)(5)(6));
function fn(num1) {
    return function (num2) {
        return function (num3) {
            return function (num4) {
                return num1 * num2 * num3 * num4;
            }
        }
    }
}

 

关注微信公众号“icketang”,获取最新前端资讯,学习资料  

微信个人号二维码.jpg
完整笔记、web前端视频教程
,请添加微信“haomei0452”免费领取 


B站搜索“爱创课堂网络科技” 免费观看前端视频以及项目实战


QQ图片20190401143635.jpg


上一篇文章: JavaScript(第四天)—web前端培训
下一篇文章: JavaScript源码笔记(第六天)—前端培训机构

最新发布 | 这里有最新的文章查看更多>>

爱创推荐 | 这里有推荐的文章查看更多>>