• 递归,作用域,闭包,缓存,沙箱


    使用递归获取后代元素
       1.自己调用自己
       2.要有结束的条件
     //斐波那契 数列
            //1 1 2 3 5 8 13 21
            //1 1
            //2 1
            //3 第1项 + 第2项
            //4 第2项 + 第3项
            //5 第3项 + 第4项
    
            //n (n-2)+(n-1)
    
            function fibonacci(n){
                if(n <= 2){
                    return 1;
                }
                return fibonacci(n-1) + fibonacci(n-2);
            }
    
            console.log(fibonacci(10));
    2.作用域
     什么是作用域
        变量起作用的范围
    ### 什么是块级作用域
        JS中没有块级作用域,使用代码块限定的作用域就是块级作用域
    ### JS中的作用域叫做 词法作用域
    ### 词法作用域
        在代码写好的时候,就能确定变量的作用域,这种作用域就是词法作用域
        动态作用域(和词法作用域相对).(是词法作用域就不可能是动态作用域)
        在js当中,只有函数能创造作用域
        var num = 123;
        function f1(){
            console.log(num);  //如果是动态作用域打印的就是456 如果是词法作用域 打印123
        }
        function f2(){
            var num = 456;
            f1();
        }
        f2();

    ### 变量提升

        JS代码的运行分两个阶段
        * 预解析阶段
            * 变量名和函数提升
                将var声明的变量名和function开头的函数进行提升
                提升到当前作用域的最上方
        * 执行阶段
        注意:
            1.变量和函数同名的时候
                只提升函数,忽略变量名
            2.函数同名的时候
                都提升,但是后面的函数会覆盖前面的函数
            3.函数表达式,只会提升变量名,不会提后面的函数
            func();
            var func = function(){
                alert("你猜我会不会被调用");
            }
    
            //提升后的代码
            var func;
            func();
            func = function(){
                alert("你猜我会不会被调用");
            };
            4.变量提升只会将变量和函数提升到当前作用域的最上方
            ```js
             funciton foo(){
                var num =123;
             }
            ```
            5.变量提升是分块 <script> 的
    <script>
    foo()
    function foo(){
           console.log("第一个script标签内的函数")
     };
    </script>
    
    <script>
    foo()
    function foo(){
       console.log("第2个script标签内的函数")
    }
    </script>            
            6.条件式函数声明 能否被提升,取决于浏览器, 不推荐使用!!!
            ```
            foo();//会报错,因为未被提升
            if(true){
                function foo(){
                }
            }

            ```
    ## 作用域链
        只要是函数都有作用域,函数内部的作用域可以访问函数外部的作用域
        当多个函数嵌套的时候,就会形成一个链式的结构,这个就是作用域链
    ## 绘制作用域链图的步骤
        1.先绘制0级作用域链
        2.在全局作用域中查找,变量和函数的声明,找到之后,将所有的变量和函数用小方格放在0级作用域链上
        3.再从0级作用域链上的函数引出1级作用域链
        4.再去每一个1级作用域链中查找变量和函数的声明,找到之后.....
        5.以此重复,就画好了整个作用域链
            //f1--->全局
            function f1(){
                //f2--->f1--->全局
                function f2(){
                    //f3---->f2--->f1--->全局
                    function f3(){
                    }
                    //f4--->f2--->f1---->全局
                    function f4(){
                    }
                }
                //f5--->f1---->全局
                function f5(){
                }
            }

    注意:

           1 设置值的时候,也是访问变量
            2. 获取值的时候,是访问变量
            3.并不是在函数内部写了变量,这个变量就属于这个函数的作用域,而是必须使用var来声明变量,这个变量才会属于这个作用域

    ## 变量的搜索规则
        1.首先在访问变量的作用域中查找该变量,如果找到直接使用
        2.如果没有找到,去上一级作用域中继续查找,如果如果找到直接使用
        3.如果没有找到,继续去上一级作用域中继续查找,直到全局作用域
        4.如果找到了就用,如果没有直到就报错
     
    ## 闭包
    ### 闭包是什么
        一个封闭的对外不公开的包裹结构或空间
    ### js中的闭包是函数
    ### 闭包要解决的问题
        1、在函数外部访问不到函数内部的数据
        2、要解决的问题就是需要在外部间接的访问函数内部的数据
     
    ###闭包的原理就是作用域访问原则
            上级作用域无法直接访问下级作用域中的变量
    ### 闭包的基本结构
            闭包基本模式
            //在外部函数(foo)内创建函数(inner),在这个内部函数(inner)中,可以操作foo中的数据
            //将外部函数的返回值设置为内部函数
            //在外部调用外部函数(foo),就可以接受到返回值(内部函数)
            //使用这个内部函数,就可以在外部对外部函数里的变量进行修改
        function outer(){
            var data = "数据";
            return function(){
                return data;
            }
        }
    
        function outer(){
            var data = "数据";
            var data1 = "数据1";
            return {
                getData:function(){
                    return data;
                },
                getData1:function(){
                    return data1;
                }
            }
        }
       
         function outer(){
                var data = "数据";
                return {
                    getData:function(){
                        return data;
                    },
                    setData:function(value){
                        data = value;
                        return data;
                    }
                }
            }

    ## 闭包的作用

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

    如果把数据放在全局作用域内,那么所有人都可以随意修改,这个数据就不再可靠。
    闭包可以创建一个私有空间,在这个空间内部的数据,外部无法直接访问
    外部空间想要访问函数内部的数据,只能通过闭包提供的指定的方法,在这个方法内部可以设置一些校验规则,让数据变得更加的安全。
    如:
    function foo(){
                var name = "潘明";
                var badLevel = -1000000000000000000000000000000000;
                return {
                    getName: function () {
                        return name;
                    },
                    setName: function (value) {
                        name = value;
                        return name;
                    },
                    getBadLevel:function(){
                        return badLevel;
                    },
                    setBadLevel:function (value) {
                        //在函数外部想要修改数据
                        //只能通过函数内部的方法
                        //我们可以在函数内部定义的这个方法里
                        //设置安全措施,校验之类的操作
                        //可以保证系统的安全性和稳定性
                        if(value > 0 ){
                            throw "你敢说我坏!!!";
                        }
    
                        badLevel = value;
                        return badLevel;
                    }
                }
            }
    
    //
    
            var obj = foo();
    //        obj.setName("王二");
            obj.setBadLevel(obj.getBadLevel() * -1 * Math.pow(10,10000000));
            console.log(obj.getBadLevel());
    
       
           
     
    使用闭包获取多个变量
     function foo() {
                var name = "张国荣";
                var age = 18;
    
                return {
                    getName:function () {
                        return name;
                    },
                    getAge:function () {
                        return age;
                    }
                }
            }
    
            var obj = foo();
            console.log(obj.getName());
            console.log(obj.getAge());
    ## 闭包练习
        setTimeout的执行时机
            所有的主任务的代码执行完毕之后,去检查所有的setTimeout回调函数,如果到时间了就执行
        用闭包来解决回调函数在调用的时候访问的是全局的变量
        在闭包中创建一个变量,来单独存储当前的回调函数需要的数据,
        在调用的时候就会去使用这个单独的数据,而不是去访问全局变量
        注册点击事件的时候
        点击事件在触发的时候访问的是全局的变量
        在闭包中创建一个变量,来单独存储当前的事件处理函数需要的数据,
        在调用的时候就会去使用这个单独的数据,而不是去访问全局变量

    ## 闭包缓存
        缓存(cache):将常用的数据进行存储,以提升性能
        硬件缓存
        浏览器缓存
        CDN(Content Delivery Network)
        内存型数据库(非关系型)MongoDB Redis
    网站静态页面缓存机制
          将网页静态化,存储在服务器端
        如何用闭包实现缓存
        1、写一个闭包在闭包中创建一个对象,用来做缓存的存储对象
        2、在闭包中创建一个对象,用来做缓存的存储对象
        3、在闭包中创建一个数组,用来存储换中的键
        4、返回一个函数,这个函数需要两个参数,一个是key 一个是value
        5、在返回的函数中,判断传入的value是否为undefined
        6、如果为Undefined 则表示是获取值,就直接返回在第一步创建的缓存对象中指定的键对应的值
        7、如果不为Undefined 则表示是设置值
        8、在缓存对象中设置指定的key的值为value
        9、把key加入存储key的数组
        10、判断key数组是不是超出了缓存大小限制
        11、如果超出限制,删除数组第一个元素(使用shift),获取到删除的key
        12、使用删除的key删除缓存对象中存储的值(delete)
    ## 使用缓存解决斐波那契数列的性能问题
        就是将已经计算过的数字缓存进一个数组中,下次再来访问的时候,直接在数组中进行查找,如果找到直接使用,如果没有找到,计算后将数字存入数组,然后返回该数字
    解决方案
    基本方案:      
           var count =0 ;//计算计算次数
            function createFib(){
                var cache = [];
                function fib(n){
                    count ++;
                    //1.从cache中获取数据
                    if(cache[n] !== undefined){
                        //如果缓存中有 直接返回
                        return cache[n];
                    }
                    //如果缓存中没有 就计算
                    if(n <= 2){
                        //把计算结果存入数组
                        cache[n] = 1;
                        return 1;
                    }
                    var temp = fib(n - 1) + fib(n - 2);
                    //把计算结果存入数组
                    cache[n] = temp;
                    return temp;
                }
                return fib;
            }
    
    
    //升级版:
    //        创建缓存容器
    
            function createCache(){
                var cache = {};
                return function (key, value) {
                    //如果传了值,就说明是设置值
                    if(value !== undefined){
                        cache[key] = value;
                        return cache[key];
                    }
                    //如果没有传值,只穿了键,那就是获取值
                    else{
                        return cache[key];
                    }
                }
            }
    
            var count =0 ;
            function createFib(){
                var fibCache = createCache();
                function fib(n){
                    count ++;
                    //1.从cache中获取数据
                    if(fibCache(n) !== undefined){
                        //如果缓存中有 直接返回
                        return fibCache(n) ;
                    }
                    //如果缓存中没有 就计算
                    if(n <= 2){
                        //把计算结果存入数组
                        fibCache(n , 1) ;
                        return 1;
                    }
                    var temp = fib(n - 1) + fib(n - 2);
                    //把计算结果存入数组
                    fibCache(n, temp) ;
                    return temp;
                }
    
                return fib;
            }
    
    
            var fib = createFib();
    //        console.log(fib(6));
            fib(5);
            console.log(count);
            count = 0;
            fib(6);
            console.log(count);
            count = 0;
            fib(20);
            console.log(count);
            count = 0;
            fib(21);
            console.log(count);
            count = 0;

    缓存:

    jQuery 实现缓存      
             function createCache(){
                //cache对象中以键值对的形式存储我们的缓存数据
                var cache = {};
                //index数组中该存储键,这个键是有顺序,可以方便我们做超出容量的处理
                var index = [];
                return function (key, value) {
                    //如果传了值,就说名是设置值
                    if(value !== undefined){
                        //将数据存入cache对象,做缓存
                        cache[key] = value;
                        //将键存入index数组中,以和cache中的数据进行对应
                        index.push(key);
    
                        //判断缓存中的数据数量是不是超出了限制
                        if(index.length >= 50){
                            //如果超出了限制
                            //删除掉最早存储缓存的数据
                            //最早存入缓存的数据的键是在index数组的第一位
                            //使用数组的shift方法可以获取并删除掉数组的第一个元素
                            var tempKey = index.shift();
                            //获取到最早加入缓存的这个数据的键,可以使用它将数据从缓存各种删除
                            delete cache[tempKey];
                        }
                    }
                    //如果没有传值,只穿了键,那就是获取值
    //                else{
    //                    return cache[key];
    //                }
                    return cache[key];
                }
            }

    ## 沙箱模式
        沙箱模式就是一个封闭的独立的环境,外界无法修改该环境内任何信息,沙箱内的东西单独属于一个世界
          360沙箱模式
          将软件和操作系统进行隔离,以达到安全的目的
          苹果手机的app使用的就是沙箱模式去运行
           隔离app的空间,每个app独立运行
     
        沙箱模式的基本模型
        (function(){
            //变量定义
            //逻辑代码
            //如果需要,向window对象添加成员,以暴露接口
        })()   //IIFE
    为什么要使用立即执行函数表达式(匿名函数)(IIFE)?
    因为IIFE不会再外界暴露任何的全局变量,但是又可以形成一个封闭的空间,刚好可以实现沙箱模式
    //jQuery当中的沙箱模式
            (function(win){
    
                var itcast = {
                    getEle:function () {
    
                    }
                }
    
                //如果需要在外界暴露一些属性或者方法,就可以将这些属性和方法
                //加到window全局对象上去
                //但是这window全局对象不可以直接引用,因为直接引用会破坏沙箱原则
                //所以我们选择使用传参的形式将 window对象 传入沙箱内
                //此时沙箱内使用window对象的时候,不会再去全局搜索window对象
                //而使用的就是沙箱内部定义的形参
    
                win.itCast = win.$ = itcast;
    
            })(window)
    
           //沙箱模式一般应用在书写第三方框架
            //或者为第三方框架书写插件
            //或者书写功能独立的一些组件
    
    
            //沙箱模式的优势
            //1.沙箱模式使用的是IIFE,不会再外界暴露任何的全局变量,也就不会造成全局变量污染
            //2.沙箱中的所有数据,都是和外界完全隔离的,外界无法对其进行修改,也就保证了代码的安全性
    
    

            //js中沙箱模式的实现原理就是
            //函数可以构建作用域!上级作用域不能直接访问下级作用域中的数据
    
    
      
     
  • 相关阅读:
    Json基本使用方法
    Java编程思想(20170818)
    FireFox加载Lodop控件
    泛型
    设计模式原则
    设计模式
    设计模式3.1:简单工厂模式
    设计模式2,模板方法
    spring -- AutoCloseable 作用
    spring 源码方法概要
  • 原文地址:https://www.cnblogs.com/aimeeblogs/p/9520645.html
Copyright © 2020-2023  润新知