<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                [TOC] ## previously 函數執行形成一個私有作用域,保護里面的私有變量不受外界干擾就叫閉包 ### 作用域 [棧內存] > 全局作用域:window > 私有作用域:函數執行 > 塊級作用域:使用let創建變量,存在塊級作用域中 ### 作用域鏈 當前作用域代碼執行的時候遇到一個變量,我們首先看一下它是否屬于私有變量,如果是當前作用域私有變量,那么以后在私有作用域中再遇到這個變量都是操作私有的(“閉包:私有作用域保護私有變量不受外界干擾”);如果不是私有的變量,向其上級作用域查找,如果也不是上級作用域私有的,就會繼續向上查找,直到找到window全局作用域,我們把這種向上一級級查找的機制叫做`作用域鏈` 全局下有,操作的就是全局變量,全局下沒有(設置:給全局對象window增加了屬性名&&獲取:報錯) ## 查找私有變量 >JS中的私有變量有且只有兩種 >- 在私有作用域變量提升階段聲明過的變量或則函數 >- **形參**也是私有變量 ``` function fn(num1,num2){ var total = num1+num2; return total; } var result = fn(100,200); ``` >函數執行形成一個全新獨立的私有的作用域 >1、 形參賦值 >2、 變量提升 >3、 代碼自上而下執行 >4、 當前棧內存(私有作用域)銷毀或則不銷毀 **注意:** 形參賦值在變量提升之前 ``` var x=10 ,y = 20 ,z = 30; function fn(x,y){ //=>[私有作用域] //=>形參賦值:x=10 y=20 (x/y都是私有變量) //=>變量提升:var x(忽略的,已經存在這個名字了) console.log(x,y,z); //=>z不是私有變量,是全局變量 var x = 100; //=>私有的x=100 y = 200; //=>私有的y=200 z = 300; //=>全局的z=300 console.log(x,y,z); //=>100 200 300 } fn(x,y,z); //=>FN執行傳的的是實參(實參都是值,不是指要轉換成值,這里傳遞的不是變量,而是變量的值傳過去了) console.log(x,y,z); //=>10 20 300 ``` FN執行傳的的是實參(實參都是值,不是指要轉換成值(**這個值可能是地址**),這里傳遞的不是變量,而是變量的值傳過去了) ``` //=>[私有作用域] //=>形參賦值:b=1 (私有變量) //=>變量提升:b=aaafff111(此處賦值操作替換了形參賦值的內容) function fn(b){ console.log(b); //=>函數b本身 function b(){ //=>[私有作用域] //=>形參賦值和變量提升都沒有 console.log(b); } b(); //=>函數b本身 } fn(1); ``` ## 如何查找上級作用域 ``` var n = 10; function sum(){ console.log(n); } // sum(); //=>10 ~function(){ var n = 100; sum(); //=>10 //sum的宿主環境(和箭頭函數的宿主環境定義貌似不一樣)是當前自執行函數形成的私有作用域,宿主環境和上級作用域沒有關系 }(); ``` >函數執行形成一個私有作用域(A),A的上級作用域是誰,和它在哪執行沒有關系,主要是看他在哪定義的,在哪個作用域下定義的,當前A的上級作用域就是誰。 ``` var n = 10; var obj = { n:20 ,fn:(function(){ var n = 30; //->上級作用域:全局作用域 return function(){ //->上級作用域:自執行函數 console.log(n); } })() }; obj.fn(); //30//return function(){console.log(n);} ``` 以上栗子,在堆內存中存obj的時候,遇到fn,發現是一個函數自執行,于是開始函數自執行,開辟一個棧內存,形參賦值,變量提升,逐行執行,然后return function,因為是function,此時會另外再開辟一個堆內存,返回堆內存的地址,作為return 返回的值。 ![](https://box.kancloud.cn/6365e868e9eaf1dd13377a63ce6aa60b_1723x367.png) ``` var n = 10; var obj = { n:20 ,fn:(function(n){ //->上級作用域:全局作用域 return function(){ //->上級作用域:自執行函數 console.log(n); } })(obj.n) }; obj.fn(); //會報錯 ``` ## 閉包作用之保護 >函數執行形成的私有作用域會保護里面的私有變量不受外界干擾。 ``` (function(window,undefined){ var jQuery = function(){ ... }; ... window.jQuery = window.$ = jquery; })(window); ``` ``` var Zepto = (function(){ var Zepto = function(){ ... }; ... return Zepto; })(); Zepto(); ``` 在真實項目中,我們利用這種保護機制實現團隊協作開發。(避免了多人同一個命名,導致代碼沖突的問題) ## 閉包作用之保存 > 函數執行,形成一個私有作用域,函數執行完成,形成的這個棧內存一般情況下都會自動釋放。 > >但是還有二般情況,函數執行完成,當前私有作用域中的某一部分內容被棧內存以外的其它東西(變量/元素的事件)占用了。當前的棧內存就不能釋放掉,也就形成了不銷毀的私有作用域(里面的私有變量也不會銷毀)。 ``` function fn(){ var i = 1; return function(n){ console.log(n+i++); } } var f = fn(); f(10);//11 fn()(10);//11 f(20);//22 fn()(20);//21 ``` ![](https://box.kancloud.cn/771f39d5b8dfead624a78c60d3e78f98_1359x602.png) >函數執行形成一個私有作用域,如果私有作用域中的的部分內容被外部的變量占用了,私有作用域不會銷毀。 >[形式] >函數執行返回了一個引用數據類型堆內存的地址(并且這個堆內存是隸屬于這個作用域的),在外面有一個變量接收了這個返回值,此時當前作用域就不能銷毀(想要銷毀,只需要讓外面的變量賦值為null,也就是不占用當前作用域中的內容了) ### 有return不一定銷毀 私有作用域里沒有東西被占用,就會銷毀。 ### 不銷毀不一定要有return ``` //這種形式私有作用域也不會銷毀 for(var i=0;i<oList.length;++i){ ~function(i){ oList[i].onclick = function(){ changeTab(i); } //沒有return 但被事件綁定占用 }(i) } ``` 另外要注意,不是你return一個堆內存就不會銷毀(上面的例子并沒有return),而是要看return的這個是否被占用,如果沒有變量來接收,是直接會銷毀的 ### 閉包保存在循環中的應用 ``` //這樣達不到預期的效果 for (var i=0;i<oList.length;++i){ oList[i].onclick = function(){ changeTab(i); //=>不行的原因,給當前LI點擊事件綁定方法的時候,綁定的方法并沒有執行(點擊的時候才執行),循環3此,分別給3個LI的點擊事件綁定了方法,循環完成后i=3(全局的)。當點擊的時候,形成一個私有作用域,用到了變量i,i不是私有的變量,向全局查找,此時全局的i已經是最后循環的3了 } } //--- --- --- for(var i=0;i<oList.length;++i){ oList[i].onclick = (function(i){ return function(){ changeTab(i); } })(i) } //--- --- --- //這種形式私有作用域也不會銷毀 for(var i=0;i<oList.length;++i){ ~function(i){ oList[i].onclick = function(){ changeTab(i); } }(i) } //--- --- --- //塊級作用域 每次循環都會形成一個單獨的{}塊級作用域,每個塊級作用域之間沒有沖突 for (let i=0;i<oList.length;++i){ oList[i].onclick = function(){ changeTab(i); } } ```
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看