最新公告
  • 欢迎您光临网站无忧模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 递归与闭包

    正文概述 掘金(Jacky010)   2021-04-07   401

    递归

    • 什么是递归?

    在程序中,递归就是函数自己直接或间接的调用自己。

    • 递归的要素?

      1 自己调用自己

      2 要有结束条件

    • 化归思想

    将一个问题由难化易,由繁化简,由复杂化简单的过程称为化归,它是转化和归结的简称。

    这里更多的是根据一些例子来体会和感受递归的思想,让我们开始吧!

    栗子1: 求1~100之和

      // 将求100转换为求99
      // 将求99转换为求98
      // ...
      // 将求2转换为求1
      // 求1结果就是1
      // 即:sum(1)是1
      function sum(n){
        if(n == 1){
          return 1;
        }
        return sum(n - 1) + n;
      }
      
      var num = sum(100);
      console.log(num); // 5050
    

    栗子2: 求阶乘

      // 1!  1
      // 2!  1! * 2
      // 3!  2! * 3
      // ...
      // n!  (n-1)! * n
      function factorial(n){
        if( n == 1){
          return 1;
        }
        return factorial(n - 1) * n;
      }
      
      // 5! = 1 * 2 * 3 * 4 * 5
      console.log(factorial(5)); // 120
    

    栗子3: 求幂

      // 1 的 m 次方   1 * 1^(m - 1) = 1^m = 1
      // 2 的 m 次方   m 个 2 相乘 2 * 2^(m - 1) = 2^m
      // ...
      // n 的 m 次方   m 个 n 相乘 即 n * n^(m - 1) = n^m
      // 每个数的 1 次方都等于它本身,如2^1 = 2; 3^1 = 3 等
      function power(n, m){
        if(m == 1){
          return n;
        }
        return power(n, m-1) * n;
      }
      console.log(power(4,3)); // 48  //4*4*4=48
    

    栗子4: 斐波那契数列

      // 斐波那契数列: 1 1 2 3 5 8 13 21 34 ...
      // 从第三项开始,后面一项的值为前面两项相加之和
      
      // 第一项  1
      // 第二项  1
      // 第三项  1 + 1 = 2
      // 第四项  1 + 2 = 3
      // ...
      // 第n项   (n - 2) + (n - 1) = n
      function fibonacci(n){
        if(n <= 2){
          return 1;
        }
        return fibonacci(n - 2) + fibonacci(n - 1);
      }
      console.log(fibonacci(10)); //55
    

    栗子5: 给页面中的所有元素添加边框

      // DOM中没有直接获取后代元素的API
      // 可以通过chaildNodes来获取所有的子节点
      
      function getChildNodes(node){
        // 先找子元素
        var nodeList = node.childNodes;
        // 再用子元素找子元素(递归)
        // for循环中的条件,就充当了结束条件
        for(var i = 0; i < nodeList.length; i++){
          // childNode获取到的节点包含了各种类型的节点 
          // 只需要元素节点 通过nodeType判断当前节点是否为元素节点
          // 节点.nodeType == 1 元素节点/2 属性节点/3 文本节点
          var childNode = nodeList[i];
          // 判断是否为元素节点
          if(childNode.nodeType == 1){
            childNode.style.border = '1px solid red';
            getChildNodes(childNode);
          }
        }
      }
      
      getChildNode(document.body);
    

    代码优化升级:

      function getChildNode(node){
        var nodeList = node.childNodes;
        var res = [];
        
        for(var i = 0; i < nodeList.length; i++){
          var childNode = nodeList[i];
          if(childNode.nodeType ==1){
            res.push(childNode);
            var temp = getChildNode(childNode0;
            res = res.concat(temp);
          }
        }
        return res;
      }
      
      // 1. 第一次调用时获取body的所有子元素,会把所有的子元素全部放到res里面
      // 2. 每放进去一个就找这个子元素的所有子元素 有返回值
      // 3. 把这个返回值和存当前子元素的数组拼接起来,就变成子元素和孙子元素的集合
      var arr = getChildNode(document.body);
      
      for(var i = 0; i < arr.length; i++){
        var child = arr[i];
        child.style.border = '1px solid red';
      }
    

    效果如下图:

    递归与闭包

    闭包

    概念

    • 什么是闭包?

    函数中的函数,里面的函数可以访问外面函数的变量,外面的变量是这个内部函数的一部分。

      function outer(){
        var num = 0; // 内部变量
        return function add(){ // 通过返回add函数,即可在outer外访问
            num++; // 内部函数引用,作为add函数的一部分了
            console.log(num);
        }
      }
      
      var func = outer();
      func(); // 1
      func(); // 2
    
    • 闭包的原理?

    作用域访问原则: 上级作用域无法直接访问下级作用域中的变量

    • 闭包解决什么问题?

    1)闭包内的数据不允许外界访问

    2)要解决的问题就是间接访问该数据

      function foo(){
        var num = 123;
        return num;
      }
      
      var x = foo(); // 使用return关键字将函数内部的数据返回,这个数据只能被使用一次
      console.log(x); // 123 
      // 上述代码在函数外部访问到了内部变量
      
      // 再定义一个y,x 是否和y相等
      var y = foo();
      console.log(y); // 123
      console.log(x === y); // true
      // 因为都是数值类型所以肯定两者是相等的,那如果是引用类型呢?
    

      function foo(){
        var obj = {
            name: '张三';
        }
        return obj;
      }
      var o1 = foo();
      var o2 = foo();
      console.log(o1 == o2); // false
      // 所以可知函数的每次调用,返回的对象都是新的,每次都不一样
    
    • 闭包的基本模式
      function outer(){
        var num = 123;
        return function inner(a){
            // 若传参数,a肯定不是undefined,所以条件判断为true
            if(a !== undefined){
                num = a;
            }else{ // 若不传参,代表获取值直接return
                return num;
            }
        }
      }
      
      var func = outer();
      func(456); // 456
    

    1)在外部函数(outer)内创建函数(inner),在这个内部函数(inner)中,可以操作外部函数(outer)中的数据

    2)将外部函数(outer)的返回值设置为内部函数(inner)

    3)在外部调用外部函数(outer),就可以接收到返回值(内部函数)

    4)使用这个内部函数(inner),就可以在外部对内部函数(inner)里的变量进行修改

    使用闭包获取多个数据

      function bar(){
        var name = '张三';
        var age = 18;
        
        // 使用对象返回多个方法,获取并设置值
        return {
            getName: function(){
                return name;
            },
            getAge: function(){
                return age;
            },
            
            // 还可以添加方法,设置值的方法
            setName: function(value){
                name = value;
                return name; // 可省略
            },
            setAge: function(value){
                age = value;
                return age; // 可省略
            }
        }
      }
      
      var obj = bar();
      console.log(obj.getName()); // 张三
      console.log(obj.getAge()); // 18
      console.log(obj.setName('李四')); // 李四
      console.log(obj.setAge('20')); // 20
    

    闭包的作用

      function bar(){
         var name = '张三';
         var age = 18;
         
         return {
            getName: function(){
                return name;
            },
            setName: function(value){
                name = value;
                return name; // 可省略
            }
         }
      }
      
      var obj = bar();
      obj.name('李四');
      
    

    作用:

    最基本的作用: 可以通过闭包返回函数或者方法,用来修改函数内部的数据。

    创建一个私有的空间,保护数据;外部想要访问数据,只能通过函数提高的方法,在提供的方法中,可以设置一些校验逻辑,让数据变得更加安全。

    闭包的练习

    线程: 一个线程一次只能处理一件事情,多个线程就可以同时执行多个事情

    Javascript是单线程的!!!

    Javascript分了三个任务:

    1)渲染任务

    2)js的代码执行任务

    3)事件处理任务

    Javascript代码的执行任务:

    1) 先把主任务(代码任务)执行完毕

    2)再去执行次要的任务(包括setTimeout和setInterval中的回调函数中的代码)

    setTimeout功能:至少在指定时间后执行指定回调函数,因为要等主任务中的代码执行完毕之后,才回去检查setTimeout的会带函数,有没有到执行时间。

    如问题代码:

      for(var i = 0 ; i < 10; i++){
         setTimeout(function(){
            console.log(j); // 输出10次10
         },0);
      }
     
    

    解决问题代码:

      for(var i = 0; i < 10; i++){
         function bar(j){
            return function(){
                console.log(i); // 0 1 2 3 4 5 6 7 8 9
            };
         }
    
         var f = bar(i);
         setTimeout(f, 0);
      }
    

    栗子: 获取div,点击打印对应的div序号

      var divs =document.getElemetsByTagNmae('div');
      for(var i = 0; i < divs.length; i++){
        var div = divs[i];
        
        div.onclick = function(j){
            return function(){
                console.log('我是第' + (j + 1) + '个div');
            }
        }(i);
      }
      
      // 立即执行函数表达式
      
      (funciton(){
        console.log('xxx');
      }());
      
    

    下载网 » 递归与闭包

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元