• <fieldset id="8imwq"><menu id="8imwq"></menu></fieldset>
  • <bdo id="8imwq"><input id="8imwq"></input></bdo>
    最新文章專題視頻專題問答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| 精品人妻伦一二三区久久| 精品亚洲综合在线第一区| 久久er99热精品一区二区| 午夜精品久久久久9999高清| Aⅴ精品无码无卡在线观看| 国产精品露脸国语对白| 亚洲第一区精品观看| 精品国产青草久久久久福利| 欧美亚洲精品在线| 国产精品jizz视频| 日韩AV无码精品人妻系列| 免费精品国产自产拍在线观看| 99热精品毛片全部国产无缓冲| 久久se精品一区二区| 国产亚洲精品a在线无码| 无码国内精品人妻少妇蜜桃视频| 香蕉99久久国产综合精品宅男自| 国产亚洲精品国看不卡| 国产成人精品久久综合| 2022精品国偷自产免费观看| 久久99国产精品久久| 成人精品综合免费视频| 99久久久精品免费观看国产| 精品国精品无码自拍自在线| 精品蜜臀久久久久99网站| 久久久精品2019免费观看| 人人妻人人澡人人爽人人精品电影| 亚洲日韩国产精品第一页一区| 亚洲欧美精品一区久久中文字幕| 国产成人精品福利网站在线观看 | 精品人妻系列无码天堂| 无码日韩精品一区二区三区免费 | 无码国产精品一区二区免费模式 | 日韩精品无码免费视频| 欧美精品国产一区二区三区| 日韩精品成人亚洲专区|