遞歸和閉包

js變量的作用域:
全局作用域(全局變量) : 在函數(shù)外面聲明的變量
**生命周期(變量從聲明到銷毀): 頁面從打開到關(guān)閉.
局部作用域(局部變量) : 在函數(shù)里面聲明的變量
**生命周: 開始調(diào)用函數(shù)到函數(shù)執(zhí)行完畢

1.閉包使用介紹

1.閉包介紹(closure)
1.1 閉包 : 是一個(gè)可以在函數(shù)外部訪問函數(shù)內(nèi)部變量的函數(shù)
* 閉包是函數(shù)
1.2 閉包作用: 可以在函數(shù)外部訪問函數(shù)內(nèi)部變量
* 延長(zhǎng)局部變量的生命周期
1.3 閉包語法 :
a. 在外部函數(shù)outer的內(nèi)部聲明了一個(gè)閉包函數(shù)closure
b. 在閉包函數(shù)內(nèi)部 返回想要訪問的局部變量
c. 在外部函數(shù)中返回閉包函數(shù)
1.4 閉包本質(zhì):
是一個(gè)溝通函數(shù)內(nèi)部(局部作用域)與函數(shù)外部(全局作用域)的橋梁

//1.需求:在函數(shù)外部訪問函數(shù)內(nèi)部的變量
        // function fn(){
        //     var zhangsan = {
        //         name:'張三',
        //         age:34
        //     };
        // };

        // fn();
        // 函數(shù)里面的局部變量在函數(shù)之后完畢之后自動(dòng)被系統(tǒng)回收
        // console.log(zhangsan);

 // 2. return返回值
        // 弊端 :浪費(fèi)內(nèi)存資源。  每調(diào)用一次函數(shù),就生成了一個(gè)新的對(duì)象
        // function fn(){
        //     var zhangsan = {
        //         name:'張三',
        //         age:34
        //     };

        //     return zhangsan;
        // };

        // var a = fn();
        // console.log(a);

        // var b = fn();
        // console.log(b);

        // //a和b是同一個(gè)對(duì)象嗎?
        // //每調(diào)用一次函數(shù)支鸡,就生成了一個(gè)新的對(duì)象受葛。兩個(gè)對(duì)象雖然數(shù)據(jù)是一樣巫橄,但是在堆中兩個(gè)不同的地址
        // console.log(a == b);

//3.使用閉包實(shí)現(xiàn)在函數(shù)內(nèi)部訪問函數(shù)外部的變量
       //聲明外部函數(shù)
         function fn(){
            var zhangsan = {
                name:'張三',
                age:34
            };

            //閉包函數(shù)
            function closure(){
                // console.log(canglaoshi);
                return zhangsan;
            };

            return closure;
            
        };

        //調(diào)用fn群嗤, (1)聲明了一個(gè)對(duì)象張三(0xaaaa)  (2)聲明了一個(gè)閉包函數(shù)closure(0xbbbb)  (3)返回閉包函數(shù)
        var bibao = fn();

        //調(diào)用閉包函數(shù):得到fn中的局部變量
        var a = bibao();
        console.log(a);
        
        var b = bibao();
        console.log(b);

        console.log(a == b);//true

2.閉包函數(shù)的使用步驟和注意點(diǎn)

1.復(fù)習(xí)閉包的語法步驟(3個(gè)步驟)
a.在外部函數(shù)outer中聲明一個(gè)函數(shù)closure
b.在閉包函數(shù)中返回想要訪問的變量
c.返回閉包函數(shù)
2.了解閉包語法的注意點(diǎn)
a. 如果希望訪問同一個(gè)變量扑庞,外部函數(shù)只能調(diào)用一次
b. 如果希望訪問不同的變量淡溯,外部函數(shù)可以調(diào)用多次
* 每調(diào)用一次生成一個(gè)新的局部變量和新的閉包函數(shù)

 function outer(){
            var num = Math.floor(Math.random()*100);
            console.log(num);
            //1.聲明閉包函數(shù)
            function closure(){
                console.log(num);
                //2.在閉包函數(shù)中返回想要訪問的變量
                return num;
            };
            //3.返回閉包函數(shù)
            return closure;
        };


        //第一個(gè)注意點(diǎn):  如果希望閉包訪問的是同一個(gè)變量读整,外部函數(shù)只能調(diào)用一次
        //1.調(diào)用outer : 聲明局部變量,聲明閉包函數(shù)
        //獲取閉包函數(shù)
        var bibao = outer();

        //2.調(diào)用閉包函數(shù)
        bibao();
        bibao();
        bibao();


        //第二個(gè)注意點(diǎn): 如果希望閉包訪問的是不同的變量咱娶,外部函數(shù)需要調(diào)用多次
        // var bibao1 = outer();
        // bibao1();
        outer()();

        //  var bibao2 = outer();
        //  bibao2();
        outer()();

        //  var bibao3 = outer();
        //  bibao3();
        outer()();

         //2米间。示例 投票機(jī)

         function vouter(){
             var num = 10;

             function closure(){
                 num++;
                 console.log(num);
                 return num;
             };
             return closure;
         };

         //2.1 一臺(tái)投票機(jī)强品,投3票
         var bb = vouter();

         bb();//11
         bb();//12
         bb();//13

         //2.2  三臺(tái)投票機(jī),各投1票
         var bb1 = vouter();
         bb1();//11

        //  var bb2 = vouter();
        //  bb2();//11
        vouter()();

        //  var bb3 = vouter();
        //  bb3();//11
        vouter()();

3.由一個(gè)練習(xí)題看閉包的本質(zhì)

  //1.
        var name = 'My Window';
        var obj = {
            name:'My Object',
            getFunction:function(){
                return function(){
                    console.log(this.name);
                };
            }
        };

        //(1) var fn = obj.getFunction()    (2)fn() // window.fn()
        // (1)當(dāng)調(diào)用obj.getFunction()的時(shí)候返回一個(gè)匿名函數(shù) (返回到全局作用域)
        //(2)調(diào)用匿名函數(shù)屈糊,由于全局的所以函數(shù)指向window
        obj.getFunction()();//'My Window';


        //2.
        var name = 'My Window';
        var obj = {
            name:'My Object',
            getFunction:function(){
                var that = this;
                return function(){
                    console.log(that.name);
                };
            }
        };

        //(1)調(diào)用obj.getFunction()  : 這個(gè)函數(shù)中this是obj ,聲明了一個(gè)局部變量that存儲(chǔ)this
        //(2)調(diào)用閉包函數(shù)的榛,由于閉包函數(shù)延長(zhǎng)了that的生命周期,所以會(huì)打印obj.name屬性值
        console.log(obj.getFunction()()); //My Object

4.閉包的經(jīng)典使用場(chǎng)景

  /* 
        1.沙箱模式:是js的一種設(shè)計(jì)模式逻锐。 一個(gè)獨(dú)立的作用域完成獨(dú)立的功能夫晌,通常是一個(gè)匿名函數(shù)自調(diào)用
        2.沙箱模式好處
            a. 封閉的空間,避免全局變量污染
            b. 模塊化開發(fā)(一個(gè)功能模塊對(duì)應(yīng)一個(gè)作用域)
         */
         (function(w){
             var person = {
                 name:'張三',
                 age:18
             };
             person.eat = function(){
                 console.log('今天吃米粉');
             };
             person.play = function(){
                 console.log('大吉大利昧诱,今晚吃雞');
             };
             /* 
             1.外部如何訪問沙箱中的變量晓淀?
             2.使用參數(shù)
                為什么不直接使用window?
                    a.沙箱里面不能直接訪問外部變量,破壞封裝性
                    b.以后實(shí)際開發(fā)代碼會(huì)壓縮,可能會(huì)把window壓縮成w盏档。直接使用無法獲取的
              */
             w.person = person;
         })(window);

         console.log(person);
         person.eat();

遞歸

1.遞歸函數(shù): 函數(shù)自己調(diào)用自己
2.遞歸函數(shù)的特點(diǎn)
a.能用遞歸實(shí)現(xiàn)的功能就一定可以使用循環(huán)調(diào)用函數(shù)來實(shí)現(xiàn),只是語法簡(jiǎn)潔性與性能不同而已
b.一定要有結(jié)束條件,否則會(huì)導(dǎo)致死循環(huán)
注意:遞歸不可以亂用,因?yàn)樵谟行r(shí)候性能不好

1.遞歸的簡(jiǎn)使用

    //遞歸
        var i = 1;
        function fn(){
            console.log('吾日三省吾身');
            i++;
            if(i<=3){
                fn();
            }; 
        };
        fn();


       // 循環(huán)
        for(var i = 1;i<=3;i++){
            fn();
        }
        function fn(){
            console.log('吾日三省吾身');
        };

2.遞歸的使用場(chǎng)景

//1.求1-n的累加和

        //遞歸實(shí)現(xiàn)
        function getSum(n) {
            if (n == 1) {
                return 1;
            } else {
                return getSum(n - 1) + n;
            };
            //遞歸分析
            // if(n == 1){
            //     return 1;
            // }else if(n == 2){
            //     return getSum(n-1) + n;
            // }else if(n == 3){
            //     return getSum(2) + 3;
            // }else if(n == 4){
            //     return getSum(3) + 4;
            // }else if(n == 5){
            //     return getSum(4) + 5;
            // }
            // ***
            // else if(n == n){
            //     return getSum(n-1)  + n
            // }
        };

        console.log(getSum(5));//1+ 2 + 3 + 4 + 5 = 15


 //循環(huán)實(shí)現(xiàn)
        // function getSum(n){
        //     //求和:籮筐思想三步法
        //     var sum = 0;
        //     for(var i = 1; i<=n;i++){
        //         sum+=i;
        //     };
        //     return sum;
        // };

        // console.log(getSum(100));


 //2.求階乘(*)
        /*階乘:
        5! = 5 * 4 * 3 * 2 * 1
        6! = 6 * 5 * 4 * 3 * 2 * 1
         */

        //遞歸實(shí)現(xiàn)
        function jieChen(n) {
            return n == 1 ? 1 : jieChen(n - 1) * n;
            //  if(n == 1){
            //      return 1;
            //  }else{
            //      return jieChen(n-1) * n;
            //  };

            //遞歸分析
            // if(n == 1){
            //     return 1;
            // }else if(n == 2){
            //     return jieChen(1) * 2;
            // }else if(n == 3){
            //     return jieChen(2) * 3
            // }else if(n == n){
            //     return jieChen(n-1) * n;
            // }
        };

        console.log(jieChen(5));// 5 * 4 * 3 * 2 * 1 = 120

        //階乘奇葩面試題 arguments.callee 得到的是函數(shù)本身
        var num = (function (n) { return n == 1 ? 1 : arguments.callee(n - 1) * n })(6);
        console.log(num);


 //  //循環(huán)實(shí)現(xiàn)
        //  function jieChen(n){
        //     var sum = 1;
        //     for(var i = 1 ;i<=n;i++){
        //         sum *= i;
        //     };
        //     return sum;
        //  };

        //  console.log(jieChen(6));// 5 * 4 * 3 * 2 * 1 = 120


 //3.斐波那契數(shù)列
        //了解: 遞歸函數(shù)雖然語法簡(jiǎn)潔凶掰,但是性能不是一定高于循環(huán)
       //檢測(cè)遞歸的性能,遞歸不可以亂用,因?yàn)樾阅懿缓?
        console.time();
        //遞歸實(shí)現(xiàn)
        function fib(n){

            if(n == 1 || n == 2){
                return 1;
            }else{
                return fib(n-2) + fib(n-1);
            };
            // if(n == 1 || n == 2){
            //     return 1;
            // }else if(n == 3){
            //     return fib(3-2) + fib(3-1);
            // }else if(n == 4){
            //     return fib(4-1) + fib(4-2)
            // }
        };

        console.log(fib(10));

        console.timeEnd();
        


        /* 需求:求斐波那契額數(shù)列第十列

        1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233,377妆丘,610锄俄,987,1597勺拣,2584,4181鱼填,6765药有,10946,17711苹丸,28657愤惰,46368........

        1.前面兩個(gè)數(shù)字固定  1 , 1
        2.第三個(gè)數(shù)字開始,每一個(gè)數(shù)字都是前面兩個(gè)數(shù)字的和
         */

        function fib(n) {
            var arr = [1, 1];
            for (var i = 2; i < n; i++) {
                arr[i] = arr[i - 2] + arr[i - 1];
            };
            return arr[arr.length-1];
        };

        console.log(fib(100));
        


          //  arr[2] = arr[2-2] + arr[2-1];
        //  arr[3] = arr[3-2] + arr[3-1];
        //  arr[4] = arr[4-2] + arr[4-1];

3.使用遞歸遍歷dom數(shù)

 /*  遞歸應(yīng)用場(chǎng)景:遍歷DOM樹
        
        1.需求:獲取father父元素的所有后代元素
        2.DOM的api中有沒有直接的方法可以獲取呢赘理? 沒有

        3.遞歸思路
            a宦言。遍歷父元素father
            b. 遍歷每一個(gè)子元素,找到子元素的子元素商模。然后又繼續(xù)遍歷子元素的子元素的子元素奠旺,以此類推
            形成遞歸調(diào)用

         */

         var father = document.getElementById('father');

         var list = [];//存儲(chǔ)所有的后代元素

         function houDai(ele){
             for(var i = 0;i<ele.children.length;i++){
                list.push(ele.children[i]);
                //遞歸求子元素的子元素
                houDai(ele.children[i]);
             };
         };

         //求父元素的所有后代元素
        //  houDai(father);
        //  console.log(list);

        //求整顆dom樹
        houDai(document);
        console.log(list);
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市施流,隨后出現(xiàn)的幾起案子响疚,更是在濱河造成了極大的恐慌,老刑警劉巖瞪醋,帶你破解...
    沈念sama閱讀 218,284評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件忿晕,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡银受,警方通過查閱死者的電腦和手機(jī)践盼,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門鸦采,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人咕幻,你說我怎么就攤上這事渔伯。” “怎么了谅河?”我有些...
    開封第一講書人閱讀 164,614評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵咱旱,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我绷耍,道長(zhǎng)吐限,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,671評(píng)論 1 293
  • 正文 為了忘掉前任褂始,我火速辦了婚禮诸典,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘崎苗。我一直安慰自己狐粱,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,699評(píng)論 6 392
  • 文/花漫 我一把揭開白布胆数。 她就那樣靜靜地躺著肌蜻,像睡著了一般。 火紅的嫁衣襯著肌膚如雪必尼。 梳的紋絲不亂的頭發(fā)上蒋搜,一...
    開封第一講書人閱讀 51,562評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音判莉,去河邊找鬼豆挽。 笑死,一個(gè)胖子當(dāng)著我的面吹牛券盅,可吹牛的內(nèi)容都是我干的帮哈。 我是一名探鬼主播,決...
    沈念sama閱讀 40,309評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼锰镀,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼娘侍!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起互站,我...
    開封第一講書人閱讀 39,223評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤私蕾,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后胡桃,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體踩叭,經(jīng)...
    沈念sama閱讀 45,668評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,859評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了容贝。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片自脯。...
    茶點(diǎn)故事閱讀 39,981評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖斤富,靈堂內(nèi)的尸體忽然破棺而出膏潮,到底是詐尸還是另有隱情,我是刑警寧澤满力,帶...
    沈念sama閱讀 35,705評(píng)論 5 347
  • 正文 年R本政府宣布焕参,位于F島的核電站,受9級(jí)特大地震影響油额,放射性物質(zhì)發(fā)生泄漏叠纷。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,310評(píng)論 3 330
  • 文/蒙蒙 一潦嘶、第九天 我趴在偏房一處隱蔽的房頂上張望涩嚣。 院中可真熱鬧,春花似錦掂僵、人聲如沸航厚。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,904評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽幔睬。三九已至,卻和暖如春芹扭,著一層夾襖步出監(jiān)牢的瞬間溪窒,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,023評(píng)論 1 270
  • 我被黑心中介騙來泰國(guó)打工冯勉, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人摹芙。 一個(gè)月前我還...
    沈念sama閱讀 48,146評(píng)論 3 370
  • 正文 我出身青樓灼狰,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親浮禾。 傳聞我的和親對(duì)象是個(gè)殘疾皇子交胚,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,933評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容