JS函数高级

2 篇文章 0 订阅

函数高级

1.回调函数 callback

  • 异步:做一个操作的时候,可以去做其他的事情 定时器

  • 同步:做一个操作的时候,其他的都只能等待 alert for

    //- 异步:做一个操作的时候,可以去做其他的事情      定时器
    console.log(1);
    setTimeout(function () { console.log("定时器"); }, 2000);
    console.log(2);
    ​
    // - 同步:做一个操作的时候,其他的都只能等待   alert  for
    alert(1);
    alert(2);
  • 回调函数:作为参数传递给其他函数调用函数,是解决异步操作的有效途径

  • 调用:等某个动作或某个行为执行完以后调用

    //- 回调函数:将函数作为参数传递给其他函数调用,解决异步操作的有效途径,等某个动作或某个行为执行完以后调用
    setTimeout(fun, 3000);
    function fun() {
        console.log("回调函数");
    }

2.匿名函数自执行(IIFE)

2.1 函数的种类

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

  • 学过的函数类型

     //1.普通函数
    function fun1(){
        console.log("普通函数");
    }
    ​
    //2.表达式函数
    var fun2 = function (){
        console.log("表达式函数");
    }
    fun2();
    ​
    //3.事件处理函数
    document.onclick = function(){
        console.log("事件处理函数");
    }
    ​
    //4.回调函数
    setTimeout(function(){ console.log("回调函数");},2000);
    ​
    //5.匿名函数
    function (){
       console.log("匿名函数");
    }

2.2 匿名函数自执行

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

    //2.匿名函数自执行  (函数的声明)(调用)
    (function () {
        console.log("匿名函数");
    })();
  • 匿名函数传参

    //3.函数传参
    (function (a, b) {
        var c = a + b;
        console.log(c);
    })(10, 20);
  • 匿名函数返回值

    //4.返回值
    var s = (function (a, b) {
        var c = a + b;
        return c;
    })(10, 20);
    console.log(s);

2.3 特点和使用场景

  • 使用场景

    • 在外部js文件的开头添加一个匿名函数自执行

    • 在不影响其他代码的基础上添加功能

    • 闭包中使用

  • 优点:

    • 避免全局污染,( 全局污染(大量使用全局变量,全局变量可以被任意的修改)

    • 完美的嵌入代码

  • 注意:再写匿名函数的时候前面加;

    ;(function(){
        console.log("匿名1");
    })()
    ;(function(){
        console.log("匿名2");
    })()

3.闭包函数(Closure)

3.1 回顾

  • 局部变量特性

    //局部变量、函数的特性
    function fun(){
        var a = 10; //局部变量,外界不能使用,除了函数的括号就会被销毁
        console.log(a++);
    }
    fun(); 
    fun(); 

3.1 闭包基础知识

  • 闭包的概念:能访问其他函数内部变量的函数(函数套函数,内部函数可以访问外部函数变量)

  • 特性:延伸变量的使用范围,闭包中使用的变量会一直存储在内存中,类似全局变量,避免污染

  • 缺点:可能造成内存泄漏, 慎用,不用的时候释放掉, f = null;

    //1.闭包:能访问其他函数内部变量的函数(函数套函数,内部函数可以使用外部函数变量)
    function outer(){
        var s = 100;
        function inner(){
            console.log(s); //100
        }
        inner();
    }
    outer();
    
    
    //2.完整的闭包
    function wai(){
        var c = 10;
        return function (){
            console.log(c++);
        }
    }
    var inn = wai(); //inn = function(){console.log(c++);}
    inn(); //10
    inn(); //11
    inn(); //12
    inn(); //13
  • 每一次闭包都是独立的模块,相互没有影响

    //2.完整的闭包
    function wai(){
        var c = 10;
        return function (){
            console.log(c++);
        }
    }
    var inn = wai(); //inn = function(){console.log(c++);}
    inn(); //10
    inn(); //11
    inn(); //12
    inn(); //13
    
    
    //每一次闭包都是独立的模块,相互没有影响
    var inn2 = wai();  //inn2 = function(){console.log(c++);}
    inn2();

3.2 闭包的使用场景

  • 使用场景1:使用函数内部变量

    //1.使用函数内部的变量
    function outer() {
        var a = 10;
        return function () {
            console.log(a++);
        }
    }
  • 使用场景2:解决全局作用域问题

    //2.解决全局作用域问题
    var arr = [];
    for (var i = 0; i < 5; i++) {
        arr.push(function () {
            console.log(i);
        })
    }
    //代码执行后的结果是?
    //arr[fun,fun,fun,fun,fun]  i = 5,条件不成立,结束循环
    //                arr[3]() = function(){console.log(i)}
    arr[3](); //5
    arr[2](); //5
    
    //使用闭包修改
    var arr1 = [];
    for (var i = 0; i < 5; i++) {
        (function (i) { //var i;
            arr1.push(function () {
                console.log(i);
            })
        })(i);
    }
    arr1[3](); //3
    arr1[2](); //2
    
  • 使用场景3:私有属性

    //3.私有属性 (idCard外界不可见,可以设置和获取)
    function Person() {
        //this.idCard = "431102200312124568";
        var idCard = "431102200312124568";
        return {
            "getId": function () {
                return idCard;
            },
            "setId":function(id){
                idCard = id;
            }
        }
    }
    var p = new Person();  // p = function(){ return idCard;}
    console.log(p);
    
    
    //获取id
    console.log(p.getId()); //431102200312124568
    
    //设置id
    p.setId("431102200412122222");
    console.log(p.getId()); //431102200412122222
  • 使用场景4:防抖和节流

3.3 闭包面试题

  • 面试题1:代码运行完后的结果是,怎么修改

    //1.面试题1:i是全局变量, 变成局部变量
    var arr = [];
    for (var i = 0; i < 5; i++) {
        (function (i) { //var i
            arr.push(function () {
                console.log(i);
            })
        })(i);
    }
    arr[3]();  //3
    arr[2]();  //2
  • 面试题2:使用闭包模拟私有变量

    //2.闭包面试题:使用闭包模拟私有属性  id外界不可见
    function Person() {
        // this.idCard = "431102200312124568";
        //设置成局部变量,外面就看不到了,但是出了函数括号就会被销毁
        var idCard = "431102200312124568";
        
        //形成闭包,闭包中使用的变量会一直存储在内存中,不会被销毁
        return {
            "getId":function(){ //获取id的函数
                return idCard;
            },
            "setId":function(id){ //设置id的函数
                idCard = id;
            }
        }
    }
    var p = new Person();
    console.log(p); //{getId: ƒ, setId: ƒ}
    
    console.log(p.getId());
    p.setId("431102200312124560");
  • 面试题3:代码执行后的结果是

    //3.闭包面试3: 代码执行后的结果
    function fun(n,o){
        console.log(o);
        return {
            "fun":function(m){
                return fun(m,n);
            }
        }
    }
    /* 
       var a = fun(0,undefined)            闭包中使用的变量会一直存储在内存中  n = 0   
          a = {
               "fun":function(m){
                   return fun(m,n);
                }
              }
        a.fun(1)  //m = 1;  fun(1,0)
        a.fun(2)  //m = 2;  fun(2,0)
        a.fun(3)  //m = 3;  fun(2,0)
    */
    var a = fun(0); //undefined
    a.fun(1);  //0 
    a.fun(2);  //0
    a.fun(3);  //0
  • 面试题4:代码执行后的结果是

    //4.闭包面试4:看代码写程序
    for(var i = 0;i<5;i++){
        setTimeout(function(){
            console.log(new Date(),i); //Thu Aug 26 2021 15:03:50 GMT+0800 (中国标准时间) 5
        },1000);
    }
    console.log(new Date(),i); //Thu Aug 26 2021 15:03:49 GMT+0800 (中国标准时间) 5

4.递归函数

  • 递归:函数内部调用函数本身

  • 和循环的区别:循环无限执行会变成死循环,卡死,递归有最大堆栈调用次数,超过会报错

4.1 阶乘

  • 递归的实现过程

    • 找规律

    • 递:函数内部调用函数本身

    • 归:在函数的开头,结束递归的执行

      //1.先找规律
      //6! 阶乘  6*5*4*3*2*1
      //6!  6 * 5!
      //5!  5 * 4!
      //4!  4 * 3!
      //n! = n * (n-1)
      
      
      //2.递://超出最大调用堆栈大小
      // function jc(n) {  
      //     return n * jc(n-1);
      // }
      // jc(6);
      
      //3.归(一定要结束)
      function jc(n){
          //归:一定是函数的开头
          if(n == 1) return 1
          //递
          return n * jc(n-1);
          //     return n * jc(n-1);
          //            // 6 * jc(5)  6*5*4*3*2*1
          //                   //5 * jc(4)  5*4*3*2*1
          //                         //4 * jc(3)  4*3*2*1
          //                               //3 * jc(2) 3*2*1
          //                                     //2 * jc(1)  1
          //                                            //1
      }
      console.log(jc(10));

4.2 斐波那契数列

  • 数列特点:1,1,2,3,5,8,13,21,34 。。。

  • 数列规律:f(n) = f(n-1) + f(n-2)

    //1.找规律  1 1 2 3 5 8 13 21 34
    //f(6) = f(5) + f(4)
    //f(5) = f(4) + f(3)
    
    //2.递
    // function rabbit(n){
    //     return rabbit(n-1) + rabbit(n-2);
    // }
    // console.log(rabbit(6)); //8
    
    
    //3.归
    function rabbit(n){
        if(n == 1 || n == 2) return 1;
        return rabbit(n-1) + rabbit(n-2);
    }
    console.log(rabbit(6)); //8
    console.log(rabbit(9)); //34

4.3 快速排序

  • 实现思路

    arr.length <=1   return arr;
       var arr = [2,7,1,5,4,6,8]
    1.获取数组中间的元素 (从数组中将中间元素删除)
      var middle = arr.aplice(arr.length/2,1)[0];
    2.创建两个空数组,left,right
    3.循环数组和中间值进行比较,比中间值小的放left,比中间值大的放后面
      middle = 5  left = [2,1,4]   right = [7,6,8]
    4.组合
      return quick(left).concat(middle,quick(right))
  • 代码实现

    function quick(arr) {
        //5.结束递归的条件
        if(arr.length<=1) return arr;
        //1.找中间值  (删除掉中间值)
        var middle = arr.splice(Math.floor(arr.length / 2), 1)[0];
    
        //2.创建两个空数组
        var left = [];
        var right = [];
    
        //3.循环数组和中间值进行比较,比中间值小的放前面,大的放后面
        for(var i = 0;i<arr.length;i++){
            if(arr[i] < middle){
                left.push(arr[i]);
            }else{
                right.push(arr[i]);
            }
        }
        //4.组合
        return quick(left).concat(middle,quick(right));
    }
    var arr = [2, 7, 1, 5, 4, 6, 8]
    console.log(quick(arr));;

5.防抖与节流

  • 作用:用于处理性能优化

5.1 防抖(debounce)

  • 防抖:在规定的事件内触发一次,开启一个定时器,延迟某个时间执行(500ms),如果在这500ms内,有再次触发事件,重新计数

  • 防抖的目的:让高频发的事件,在规定时间内,触发1次

  • 实现思路: 开一个定时器,事件延迟某个时间(30ms),如果在这30ms内再次触发整个事件,重新开始计数

  • 基础实现

    //2.在div中移动,数字+1
    oDiv.onmousemove = debounce(fun,30);
    function fun() {
        oDiv.innerText++;
    }
    
    //3.防抖:事件发生的时候开启定时器,开始计数(30),如果在计数范围内又触发了事件,那就重新开始计数
    var timer;
    function change() {
        //判断,如果之前已经开启了定时器,就清除掉之前的
        if (timer) { clearTimeout(timer) }
        timer = setTimeout(function () {
            fun();
        }, 30);
    }
  • 封装

    function debounce(fun,wait) { //fun:事件处理函数, wait:延迟事件
        var timer; //维护全局纯净,借助闭包来实现
        return function () {
            if (timer) {  //timer有值为真,这个事件已经触发了一次,重新开始计数
                clearTimeout(timer); 
            }
            timer = setTimeout(function () {
                fun();
            }, wait);
        }
    }
  • 5.2 节流
  • 在规定的事件内触发一次,开启定时器,延迟某个时间执行一次,如果在等待的这个时间内再处触发事件,不处理,控制事件的执行频率

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值