<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      javascript閉包—圍觀大神如何解釋閉包

      閉包的概念已經出來很長時間了,網上資源一大把,本著拿來主意的方法來看看。

      這一篇文章 學習Javascript閉包(Closure) 是大神阮一峰的博文,作者循序漸進,講的很透徹。下面一一剖析。

      1.變量的作用域

      變量的作用域有局部和全局兩種,在javascript的函數內部可以訪問全局變量,如下:

        // 函數內部可以直接讀取全局變量
        var n = 99;
        function f1() {
          alert(n);
        }
        f1();

      在f1函數中可以訪問到全局變量n。輸出如下:

      反過來就不行了,在函數外部不能讀取函數內部的變量,例如這樣:

        //函數外部無法讀取函數內部的局部變量,這里會報錯
        function f2() {
          var m = 99;
        }
        alert(m) //報錯

      javascript還有一個比較特殊的地方,在函數內部如果沒有使用var,const,let修飾符聲明變量,那么這個變量不再是局部變量而是一個全局變量,如下:

        function f2() {
          m = 99;
        }
        f2();
        alert(m)

      輸出99:

      是不是很神奇,但是這個經常給人造成困惑。

       

      2.如何從外部讀取函數內部的局部變量

      很多場合下要訪問函數內部的局部變量,變通的方式是在函數內部定義函數,如下:

        function f3() {
          var a = 999;
      
          function f4() {
            alert(a);
          }
          return f4
        }
        var result = f3();
        result();

      函數f4包含在函數f3里面,所以f4范圍內可以訪問到f3中的那個變量a,反過來是不行的,Javascript語言特有的"鏈式作用域"結構(chain scope),子對象會一級一級地向上尋找所有父對象的變量。所以,父對象的所有變量,對子對象都是可見的,反之則不成立。

       

      3.閉包的概念

      可以簡單理解成定義在函數內部的函數,這個內部函數可以把內部函數作用域內的變量傳播到外面。由于在javascript中只有內部的子函數才能讀取局部變量,因此可以把閉包簡單的理解成“定義在一個函數內部的函數”。本質上,閉包就是將函數內部和函數外部連接起來的橋梁。

       

      4.閉包的作用

      閉包的第一個用處就是讀取函數內部的變量,另一個作用就是讓這些變量始終保存在內存中。來看下面的代碼:

        function f5() {
          var b = 111;
          nAdd = function () {
            b += 1;
          }
          function f6() {
            alert(b);
          }
          return f6
        }
        var result1 = f5();
        result1();
        nAdd();
        result1();

      上面代碼兩次彈出框,第一次是輸出111,第二次是112,這就證明函數函數f5內的局部變量b一直保存在內存中,并沒有在f5調用后被自動清除。

      這就說明,第一次調用result1();的時候給變量b賦值了,然后調用全局函數nAdd的時候變量b仍然還在內存中,給他加1就變成112了。原因就在于f5是f6的父函數,而f6被賦給了一個全局變量,這導致f6始終在內存中,而f6的存在依賴于f5,因此f5也始終在內存中,不會在調用結束后,被垃圾回收機制(garbage collection)回收。

      這段代碼中另一個值得注意的地方,就是"nAdd=function(){n+=1}"這一行,首先在nAdd前面沒有使用var關鍵字,因此nAdd是一個全局變量,而不是局部變量。其次,nAdd的值是一個匿名函數(anonymous function),而這個匿名函數本身也是一個閉包,所以nAdd相當于是一個setter,可以在函數外部對函數內部的局部變量進行操作。

      5.注意 

      1)由于閉包會使得函數中的變量都被保存在內存中,內存消耗很大,所以不能濫用閉包,否則會造成網頁的性能問題,在IE中可能導致內存泄露。解決方法是,在退出函數之前,將不使用的局部變量全部刪除。其實一般不會這樣用!!!
      2)閉包會在父函數外部,改變父函數內部變量的值。所以,如果你把父函數當作對象(object)使用,把閉包當作它的公用方法(Public Method),把內部變量當作它的私有屬性(private value),這時一定要小心,不要隨便改變父函數內部變量的值。其實一般不會這樣用!!!

      最后作者給出了思考題目,如下:

        var name = 'The Window';
        var object = {
          name: 'My Object',
          getNameFunc: function () {
            // 這里的this是函數
            console.info(this)
            return function () {
              //匿名函數的執行環境是windows
              console.info(this)
              return this.name;
            }
          }
        };
        alert(object.getNameFunc()());

      其實從變量的值已經看到答案了,在對象object內部的函數getNameFunc里面返回了一個匿名函數這個匿名函數的作用域是window,所以這里輸出的是'The Window',如下:

      我在日志里面加上的調試語句可以看出端倪:

      看下面的代碼:

        var name1 = "The Window";
        var object1 = {
          name1: 'My Object1',
          getNameFunc:function () {
            var that = this;
            return function () {
              return that.name1
            }
          }
        }
        alert(object1.getNameFunc()());

      這里在函數內部使用var that = this語句先把當前上下文的對象保存下來,在匿名函數中使用that.name1,這樣就是當前對象中的name1,于是輸出了“MyObject1”。其實可以用es6中的箭頭函數,如下:

        var name1 = "The Window";
        var object1 = {
          name1: 'My Object1',
          getNameFunc:function () {
            return  () => {
              return this.name1
            }
          }
        }
        alert(object1.getNameFunc()());

      箭頭函數會綁定object1的作用域,于是仍任是object1的屬性name1,和上面輸出的結果一樣。

      6.深入的理解

       在知乎上也有人在討論這個問題,知乎你懂的,比較嚴謹,如何通俗易懂的解釋javascript里面的‘閉包’?這一篇問答里有人給出了其他的解釋。

       1.每次定義一個函數,都會產生一個作用域鏈(scope chain)。當JavaScript尋找變量varible時(這個過程稱為變量解析),總會優先在當前作用域鏈的第一個對象中查找屬性varible ,如果找到,則直接使用這個屬性;否則,繼續查找下一個對象的是否存在這個屬性;這個過程會持續直至找到這個屬性或者最終未找到引發錯誤為止。
      ------有道理,關鍵是弄懂這個作用域鏈,說白了就是花括號的層級及各種函數的的上下文作用域,比如在函數中定義變量不用var,let它居然是全局的,這個是javascript比較特殊的地方,強類型語言估計早就報錯了。

      2.JavaScript中的函數運行在它們被定義的作用域里,而不是它們被執行的作用域里。
      ------有道理,上面的最后一個代碼段中的例子,本來執行object1.getNameFunc()()這一句的時候,執行作用域中的name1是var name1 = "The Window";這個,但是彈出來的確實定義getNameFunc這個函數的作用域內的name1: 'My Object1',

      3.子函數能夠訪問父函數的局部變量,反之則不行。而那個子函數就是閉包!
      ------有道理,就是上面阮大師反復說明的

      好了,就這么多了。

       

      posted @ 2017-03-16 20:48  nd  閱讀(903)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 少妇人妻av毛片在线看| 亚洲精品一区二区三区综合| 久久久久免费看成人影片| 亚洲第一区二区三区av| 色偷偷www.8888在线观看| 国产情侣激情在线对白| 国产成人精品亚洲午夜麻豆 | 97一期涩涩97片久久久久久久| 亚洲国产精品乱码一区二区| 国产肥臀视频一区二区三区| 亚洲午夜香蕉久久精品| 国产精品自在自线免费观看| 日本免费一区二区三区| 亚洲男人av天堂久久资源| 免费无码肉片在线观看| 欧洲中文字幕一区二区| 亚洲男人电影天堂无码| 国产亚欧女人天堂AV在线| 熟妇无码熟妇毛片| 日日噜噜夜夜狠狠久久蜜桃| 麻豆一区二区三区精品视频| 亚洲av日韩av永久无码电影| 亚洲国产精品久久久天堂麻豆宅男 | 乌拉特中旗| 国产成人啪精品午夜网站| 国产精品白浆在线观看免费| 国产精品中文第一字幕| 午夜爽爽爽男女污污污网站| 国产无码高清视频不卡| 国产精品无码无片在线观看3d | 国产精品aⅴ免费视频| 老司机亚洲精品一区二区| 午夜在线欧美蜜桃| 亚洲av午夜成人片| 日韩有码中文在线观看| 极品美女自拍偷精品视频| 韩国精品一区二区三区| 久久这里只精品热免费99| 性色av 一区二区三区| 国产一区日韩二区三区| 亚洲18禁一区二区三区|