<span id="mktg5"></span>

<i id="mktg5"><meter id="mktg5"></meter></i>

        <label id="mktg5"><meter id="mktg5"></meter></label>
        最新文章專題視頻專題問答1問答10問答100問答1000問答2000關鍵字專題1關鍵字專題50關鍵字專題500關鍵字專題1500TAG最新視頻文章推薦1 推薦3 推薦5 推薦7 推薦9 推薦11 推薦13 推薦15 推薦17 推薦19 推薦21 推薦23 推薦25 推薦27 推薦29 推薦31 推薦33 推薦35 推薦37視頻文章20視頻文章30視頻文章40視頻文章50視頻文章60 視頻文章70視頻文章80視頻文章90視頻文章100視頻文章120視頻文章140 視頻2關鍵字專題關鍵字專題tag2tag3文章專題文章專題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專題3
        問答文章1 問答文章501 問答文章1001 問答文章1501 問答文章2001 問答文章2501 問答文章3001 問答文章3501 問答文章4001 問答文章4501 問答文章5001 問答文章5501 問答文章6001 問答文章6501 問答文章7001 問答文章7501 問答文章8001 問答文章8501 問答文章9001 問答文章9501
        當前位置: 首頁 - 科技 - 知識百科 - 正文

        JavaScript閉包原理與用法實例分析

        來源:懂視網 責編:小采 時間:2020-11-27 22:10:21
        文檔

        JavaScript閉包原理與用法實例分析

        JavaScript閉包原理與用法實例分析:本文實例講述了JavaScript閉包原理與用法。分享給大家供大家參考,具體如下: 1、與閉包有關的兩個概念: 1) 變量的作用域 不帶有關鍵字var的變量會成為全局變量; 在函數中使用關鍵字var聲明的變量是局部變量。 局部變量只有在函數內部才能訪問到,在函數外
        推薦度:
        導讀JavaScript閉包原理與用法實例分析:本文實例講述了JavaScript閉包原理與用法。分享給大家供大家參考,具體如下: 1、與閉包有關的兩個概念: 1) 變量的作用域 不帶有關鍵字var的變量會成為全局變量; 在函數中使用關鍵字var聲明的變量是局部變量。 局部變量只有在函數內部才能訪問到,在函數外

        本文實例講述了JavaScript閉包原理與用法。分享給大家供大家參考,具體如下:

        1、與閉包有關的兩個概念:

        1) 變量的作用域

        不帶有關鍵字var的變量會成為全局變量;

        在函數中使用關鍵字var聲明的變量是局部變量。

        局部變量只有在函數內部才能訪問到,在函數外面是訪問不到的。但在函數內部可以通過作用域鏈一直向上搜索直到全局對象,也就是說,函數內部可以訪問函數外部的變量。

        2) 變量的生存周期

        對于全局變量,其生存周期是永久的,除非主動銷毀這個全局變量;

        而對于在函數內用關鍵字var聲明的局部變量,當退出函數時,這些局部變量會隨著函數調用結束而被銷毀。

        var func = function() {
         var i = 1;
         alert(i); // 
        輸出:1 }; alert(i); // 報錯:i is not defind.

        例外情況:閉包

        var func = function() {
         var i = 1;
         return function() {
         alert(i);
         i++;
         }
        };
        var f1 = func();
        f1(); // 
        輸出:1 f1(); // 輸出:2 var f2 = func(); f2(); // 輸出:1 f2(); // 輸出:2

        2、從閉包的一個經典應用談起

        <div>0</div>
        <div>1</div>
        <div>2</div>
        <div>3</div>
        <div>4</div>
        <script>
         var divs = document.getElementsByTagName("div");
         for (var i = 0; i < divs.length; i++) {
         divs[i].onclick = function() {
         alert(i);
         };
         }
        </script>
        
        

        問題:無論單擊哪個div,都會彈出5。

        原因:onclick事件是異步觸發的,當事件被觸發時,for循環早已結束,此時變量i的值早已經是5。

        解決:在閉包的幫助下,把每次循環的i值都封閉起來。當事件函數順著作用域鏈從內到外查找變量i時,會先找到被封閉在閉包環境的i,單擊div時,會分別輸出0,1,2,3,4。

        <div>0</div>
        <div>1</div>
        <div>2</div>
        <div>3</div>
        <div>4</div>
        <script>
        var divs = document.getElementsByTagName("div");
        for (var i = 0; i < divs.length; i++) {
         divs[i].onclick = (function(num) {
         return function() {
         alert(num);
         };
         })(i);
        }
        </script>
        
        

        類似實例:閉包直接賦給數組

        function createFunctions() {
         var result = new Array();
         for (var i = 0; i < 10; i++){
         result[i] = function(){
         return i;
         };
         }
         return result;
        }
        for (var i = 0; i < 10; i++)
         alert(createFunctions()[i]());
        
        

        結果:result的每個元素都返回10。

        說明:閉包的作用域鏈有明顯的副作用——閉包總是獲得外部函數變量的最終值。上面代碼中,外部函數產生一個函數數組result并返回。函數數組中的每個元素都是一個函數,每個函數都返回 i變量。似乎每個函數應該返回每次循環的i值,即依次返回0到9,但事實是,每個函數的返回結果都是10。這是因為每個內部函數返回的是變量i,而不是i在某個時刻的特定值,而i的作用域是整個外部函數,當外部函數執行完成后,i的值是10。

        解決:在每個內部函數的內部,再產生一個匿名函數并返回。

        function createFunctions() {
         var result = new Array();
         for (var i = 0; i < 10; i++) {
         result[i] = (function(num) {
         return function() {
         return num;
         };
         })(i);
         }
         return result;
        }
        for (var i = 0; i < 10; i++)
         alert(createFunctions()[i]());
        
        

        結果:result依次返回0到9。

        說明:(i)使得該層匿名函數立即執行。

        3、閉包

        有時候需要得到函數內的局部變量。如何從外部讀取局部變量?那就是在函數的內部,再定義一個函數。

        閉包是指有權訪問另一個函數作用域中變量的函數,創建閉包的最常見的方式就是在一個函數內創建另一個函數,通過另一個函數訪問這個函數的局部變量,利用閉包可以突破作用鏈域,將函數內部的變量和方法傳遞到外部。

        ① 閉包的原理

        1) 后臺執行環境中,閉包的作用域鏈包含著自己的作用域、函數的作用域和全局作用域。

        2) 通常,函數的作用域和變量會在函數執行結束后銷毀。

        3) 但是,當函數返回一個閉包時,這個函數的作用域將會一直在內存中保存到閉包不存在為止。

        ② 閉包的特性

        1) 函數內再嵌套函數。

        2) 內部函數可以引用外層的參數和變量。

        3) 參數和變量不會被垃圾回收機制回收。

        ③ 閉包的用途

        1) 讀取函數內部的變量。

        function f1(){
         var n = 999;
         function f2(){
         alert(n);//999
         }
        }
        
        

        在上面的代碼中,函數f2就被包括在函數f1內部,這時f1內部的所有局部變量,對f2都是可見的。但是反過來就不行,f2內部的局部變量,對f1就是不可見的。既然f2可以讀取f1中的局部變量,那么只要把f2作為返回值,就可以在f1外部讀取它的內部變量了。

        function f1(){
         var n = 999;
         function f2(){
         alert(n);
         }
         return f2;
        }
        var result=f1();
        result();//999
        
        

        閉包就是能夠讀取其他函數內部變量的函數。由于在Javascript語言中,只有函數內部的子函數才能讀取局部變量,因此可以把閉包簡單理解成"定義在一個函數內部的函數"。所以,在本質上,閉包就是將函數內部和函數外部連接起來的一座橋梁。

        function f1(){
         var n = 999;
         nAdd = function(){n += 1}
         function f2(){
         alert(n);
         }
         return f2;
        }
        var result=f1();
        result();//999
        nAdd();
        result();//1000
        
        

        result實際上就是閉包f2函數。它一共運行了兩次,第一次的值是999,第二次的值是1000。這證明了,函數f1中的局部變量n一直保存在內存中,并沒有在f1調用后被自動清除。原因就在于f1是f2的父函數,而f2被賦給了一個全局變量,這導致f2始終在內存中,而f2的存在依賴于f1,因此f1也始終在內存中,不會在調用結束后,被垃圾回收機制回收。

        2) 讓函數內部的變量的值始終保持在內存中(延長局部變量的壽命)。

        var print, add, set;
        function closure() {
         var number = 8;
         print = function() {
         alert(number);
         }
         add = function() {
         number++;
         }
         set = function(x) {
         number = x;
         }
        }
        closure();//創建一個閉包
        add();
        print();//9
        set(0);
        print();//0
        var oldClosure = print;
        closure();//創建一個新的閉包
        print();//8
        oldClosure();//0
        
        

        使用閉包的注意點:由于閉包會使得函數中的變量都被保存在內存中,內存消耗很大,所以不能濫用閉包,否則會造成網頁的性能問題,在IE中可能導致內存泄露。解決方法是,在退出函數之前,將不使用的局部變量全部刪除。也就是說,閉包會引用外部函數作用域,會占用更多的內存,過度使用閉包,會導致性能問題。所以,僅當必要時才使用閉包。對產生閉包的函數,使用后應該解除引用。

        3)自執行函數+閉包減少全局變量污染(封裝私有變量)

        var person = (function() {
         var_name = "Alice";
         var _id = 16;
         return {
         getUserInfo: function() {
         return _name + ": " + _id;
         }
         }
        })();
        
        

        使用下劃線來約定私有變量_name和_age,它們被封裝在閉包產生的作用域中,外部是訪問不到這兩個變量的,這就避免了對全局的命令污染。

        ④ 閉包的缺點:

        1) 需要維護額外的作用域。

        2) 過渡使用閉包會占用大量內存。

        4、this對象

        在閉包內使用this對象將產生一些復雜的行為。this對象的值基于函數所在的執行環境在運行時決定:在全局函數中使用時,this等于window(非嚴格模式)或undefined(嚴格模式);而當作為對象的方法調用時,this等于這個對象。

        var name = "The window";
        var object = {
         name: "My object",
         getName: function() {
         return function() {
         return this.name;
         };
         }
        };
        alert(object.getName()());//
        輸出:"The window"

        每個函數一旦被調用,它將自動獲得this和arguments兩個變量。一個內部函數是不能直接從外部函數訪問到這兩個變量的??梢酝ㄟ^將this對象存儲在另一個變量中來解決這個問題。把外部作用域中的this對象保存在一個閉包能夠訪問到的變量里,就可以讓閉包訪問該對象了。

        var name ="The window";
        var object = {
         name: "My object",
         getName: function() {
         var that = this;
         return function() {
         return that.name;
         };
         }
        };
        alert(object.getName()());//
        輸出:"My object"

        要讓閉包訪問外部函數的this和arguments對象,可以通過將它們的引用存儲在另一個變量中來完成。

        5、內存泄漏

        使用閉包的時候很容易造成循環引用,若閉包的作用域包含著一些DOM節點,這時候就有可能造成內存泄漏,但其實,這本身不是閉包的問題,而是由于:BOM和DOM中的對象是使用C++以COM對象的方式實現的,而COM對象的垃圾收集機制采用的是引用計數策略,在基于引用計數策略的垃圾回收機制中,若兩個對象之間形成了循環引用,則這兩個對象都無法被回收。

        function assignHandler() {
         var element = document.getElementById("id");
         element.onclick = function() {
         alert(element.id);
         }
        }
        
        

        匿名函數保存了一個對element的引用,只要匿名函數存在,element的引用數至少為1,它所占用的內存就永遠不會被回收。

        function assignHandler() {
         var element = document.getElementById("id");
         var id = element.id;
         element.onclick = function() {
         alert(id);
         }
         element = null;
        }
        
        

        通過把element.id的一個副本保存在變量中,并且在閉包中引用該變量消除了循環引用,但是僅僅做到這一步還不能解決內存泄漏的問題,閉包會引用包含函數的所有活動對象,包含element,即使閉包不直接引用element,包含函數的活動對象中也仍然會保存一個引用,因此有必要把element元素設置為null,這樣就能解除對DOM對象的引用,確保正?;厥掌湔加玫膬却?。

        6、模仿塊級作用域

        JavaScript中沒有直接的塊級作用域。

        function output(count) {
         for (var i = 0; i < count; i++) {
         alert(i);
         }
         alert(i);//
        輸出:10 }

        使用閉包可以模仿塊級作用域——創建并立即調用一個函數,這樣既可以執行其中的代碼,又不會在內存中留下對該函數的引用。結果是內部函數的所有變量都會立即被銷毀,除非將某些變量賦值給了包含作用域(即外部作用域)中的變量。

        用作塊級作用域的匿名函數:將函數聲明包含在一對圓括號中,表示它實際上是一個函數表達式,緊隨其后的另一對圓括號會立即調用這個函數。

        (function() {
         //這里是塊級作用域;
        }) ();
        
        

        可以使用匿名函數表達式來模擬塊級作用域,任何定義在匿名函數中的變量在匿名函數執行完之后都將被銷毀,在匿名函數外訪問這些變量將會產生錯誤。

        function output(count) {
         (function() {
         for (var i = 0; i < count; i++) {
         alert(i);
         }
         }) ();
         alert(i);//出錯
        }
        
        

        更多關于JavaScript相關內容可查看本站專題:《javascript面向對象入門教程》、《JavaScript常用函數技巧匯總》、《JavaScript錯誤與調試技巧總結》、《JavaScript數據結構與算法技巧總結》、《JavaScript遍歷算法與技巧總結》及《JavaScript數學運算用法總結》

        希望本文所述對大家JavaScript程序設計有所幫助。

        聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

        文檔

        JavaScript閉包原理與用法實例分析

        JavaScript閉包原理與用法實例分析:本文實例講述了JavaScript閉包原理與用法。分享給大家供大家參考,具體如下: 1、與閉包有關的兩個概念: 1) 變量的作用域 不帶有關鍵字var的變量會成為全局變量; 在函數中使用關鍵字var聲明的變量是局部變量。 局部變量只有在函數內部才能訪問到,在函數外
        推薦度:
        • 熱門焦點

        最新推薦

        猜你喜歡

        熱門推薦

        專題
        Top
        主站蜘蛛池模板: 亚洲成AV人片在线播放无码| 亚洲国产成人久久综合区| 特黄特色大片免费| 成人毛片免费网站| 亚洲伦理一二三四| 久久WWW色情成人免费观看| 亚洲一区在线免费观看| 乱淫片免费影院观看| 日本免费v片一二三区| 国产成人亚洲综合a∨| 亚洲国产专区一区| 在线播放免费人成视频网站| 国产a v无码专区亚洲av | 国产精品无码亚洲精品2021| 国产激情免费视频在线观看 | 日本亚洲欧洲免费天堂午夜看片女人员 | 久久久久久久久久国产精品免费| 久久WWW色情成人免费观看| 亚洲精品天堂成人片AV在线播放| 欧洲人成在线免费| 亚洲白色白色永久观看| 欧美在线看片A免费观看| 羞羞视频免费网站入口| 亚洲人成色7777在线观看| 在线看片免费人成视久网| 亚洲妇熟XXXX妇色黄| 4444www免费看| 国产精品亚洲AV三区| 久久久久久久综合日本亚洲 | 亚洲精品视频在线观看视频| 国产成人免费爽爽爽视频| 日韩精品视频在线观看免费| 亚洲国产综合专区电影在线| 成人网站免费大全日韩国产| 亚洲嫩草影院久久精品| 日韩免费无码一区二区视频| 成人精品视频99在线观看免费| 亚洲人成网网址在线看| 亚洲综合激情另类专区| 精品香蕉在线观看免费| 亚洲中文无码av永久|