淺談-閉包

 

前情紀要:上次的公司例會上的分享會上我準備了一個關於「閉包」的ppt,而後本身向部門的同事們講解了一下我對於這部份內容的理解,可是講完了以後發現本身還有不少地方說的不是很透徹。javascript


 

一:背景知識小解:java

這裏要講的閉包實際上是「javascript 中的閉包」要理解閉包的概念首先要知道一些關於js(javascript的簡稱,下面就js)的基礎知識編程

Javascript特殊的變量做用域。 swift

變量的做用域無非就是兩種:全局變量和局部變量。瀏覽器

Javascript語言的特殊之處,就在於函數內部能夠直接讀取全局變量。 緩存

另外一方面,在函數外部天然沒法讀取函數內的局部變量。閉包

 

介紹到這裏可能有人要問,爲啥不能讀取框架

這就是Javascript語言特有的「鏈式做用域」結構chain scope),函數

子對象會一級一級地向上尋找全部父對象的變量。因此,父對象的全部變量,性能

對子對象都是可見的,反之則不成立。

 

垃圾回收機制(garbage collection:垃圾收集器會按期(週期性)找出

那些不在繼續使用的變量,而後釋放其內存。

再也不使用的變量也就是生命週期結束的變量,固然只多是局部變量,

全局變量的生命週期直至瀏覽器卸載頁面纔會結束。


二:初始閉包:

這就是最簡答的一個「閉包」,

函數」和「函數內部能訪問到的變量」(也叫環境)的總和,就是一個閉包。

編程界崇尚以簡潔優雅惟美,不少時候 若是你以爲一個概念很複雜,那麼極可能是你理解錯了。

還要稍微複雜一點的閉包:

 


 

三:如何理解閉包:

閉包經常用來「間接訪問一個變量」。換句話說,「隱藏一個變量」。 假設咱們在作一個遊戲,在寫其中關於「還剩幾條命」的代碼。 若是不用閉包,你能夠直接用一個全局變量: window.lives = 30 // 還有三十條命 這樣看起來很不妥。萬一不當心把這個值改爲 -1 了怎麼辦。因此咱們不能讓別人 「直接訪問」這個變量。怎麼辦呢? 用局部變量。 可是用局部變量別人又訪問不到,怎麼辦呢? 暴露一個訪問器(函數),讓別人能夠「間接訪問」。那麼在其餘的 JS 文件,就可使用 window.獎勵一條命() 來漲命,使用 window.死一條 命() 來讓角色掉一條命。

其實我以爲閉包就是這樣一個很簡單的概念,這種概念不光光是應用在js中,

PHPScalaSchemeCommon LispSmalltalkGroovyJavaScriptRubyPythonGoLuaobjective cswift 以及JavaJava8及以上)等語言中都能找到對閉包不一樣程度的支持。

因此說對於技術來講,基本的原理都是相同的,就像如今的js中有不少在使用面向對象的思路在寫框架、寫接口、寫插件。

 


四:閉包的幾種表現形式

 

一、匿名自執行函數

var data= {    
    table : [],    
    tree : {}    
};    
     
(function(dm){    
    for(var i = 0; i < dm.table.rows; i++){    
       var row = dm.table.rows[i];    
       for(var j = 0; j < row.cells; i++){    
           drawCell(i, j);    
       }    
    }    
       
})(data);   
( function() {}() );
( function() {} )();
[ function() {}() ];

~ function() {}();
! function() {}();
+ function() {}();
- function() {}();

var f = function() {}();
下面再講-

2:結果緩存

3:封裝

4:繼承

簡單講一下3:封裝

var person = function(){    
    //變量做用域爲函數內部,外部沒法訪問    
    var name = "default";       
    return {    
       getName : function(){    
           return name;    
       },    
       setName : function(newName){    
           name = newName;    
       }    
    }    
}();    
     
alert(person.name);//直接訪問,結果爲undefined    
alert(person.getName());    
person.setName("abruzzi");    
alert(person.getName());   (演示一下吧!)
   
獲得結果以下:  
undefined  
default  
abruzzi

小總結:學習過有關「面向對象「原理的高級語言的同窗應該看出來了,這就是面向對象的思想,因此再次強調,技術是相同的


五:閉包的優缺點

優勢:

1:能夠讀取函數內部的變量,

2:讓這些變量的值始終保持在內存中,

 缺點:

1)因爲閉包會使得函數中的變量都被保存在內存中,內存消耗很大,因此不能濫用閉包,不然會形成網頁的性能問題,在IE中可能致使內存泄露。解決方法是,在退出函數以前,將不使用的局部變量所有刪除。--可是在這裏有個疑問:究竟怎麼定義內存泄漏,要是用的內存、變量還叫作泄漏嗎?

2)閉包會在父函數外部,改變父函數內部變量的值。因此,若是你把父函數看成對象(object)使用,把閉包看成它的公用方法(Public Method),把內部變量看成它的私有屬性(private value),這時必定要當心,不要隨便改變父函數內部變量的值。

 


六:一點延伸:什麼是函數申明、函數表達式

function fnName () {…
};  

 var fnName = function () {
…};

函數聲明:function fnName () {…}; 使用function關鍵字聲明一個函數,再指定一個函數名,叫函數聲明。

函數表達式: var fnName = function () {…}; 使用function關鍵字聲明一個函數,但未給函數命名,最後將匿名函數賦予一個變量,叫函數表達式,這是最多見的函數表達式語法形式。

匿名函數:function () {}; 使用function關鍵字聲明一個函數,但未給函數命名,因此叫匿名函數,匿名函數屬於函數表達式,匿名函數有不少做用,賦予一個變量則建立函數,賦予一個事件則成爲事件處理程序或建立閉包等等。

函數聲明和函數表達式不一樣之處在於,1、Javascript引擎在解析javascript代碼時會‘函數聲明提高’(Function declaration Hoisting)當前執行環境(做用域)上的函數聲明,而函數表達式必須等到Javascirtp引擎執行到它所在行時,纔會從上而下一行一行地解析函數表達式,2、函數表達式後面能夠加括號當即調用該函數,函數聲明不能夠,只能以fnName()形式調用

總結:函數聲明提高是重點,能理解了這個概念就懂了聲明和表達式的區別了。


七:關於此次分享的緣由

引起此次技術學習的一段代碼我貼出來

        var Eplus365Verifiy = (function (self) {
            self.FrameworkName = 'Eplus365Verifiy.js';
            self.FrameworkVersion = '1.0.0';
            //手機號的正則驗證
            self.MobileVerifiy = function (val) {
                var myreg = /^1[3,4,5,7,8]\d{9}$/;
                if (myreg.test(val)) {
                    return true;
                }
                return false;
            }
            //長度驗證,區分中文和字符-若是數據類型設置爲varchar才須要這方法驗證,若是是nvarchar就不要用了
            self.LengthVerifiy = function (val, length) {
                var len = getStringLen(val);
                if (len > length) {
                    return false;
                } else {
                    return true;
                }
            }
            return self;
        } (Eplus365Verifiy || {}));

        var Eplus365Verifiy = (function (self) {
            self.ss = "ss";
            return self;
        } (Eplus365Verifiy || {}))

            console.log(Eplus365Verifiy.MobileVerifiy("15235382691"));
            console.log(Eplus365Verifiy.ss);

這裏須要理解的是

1:匿名自執行函數

2:Eplus365Verifiy || {} 沒有值得時候的初始化

3:return self ;//把自己做爲一個返回值,而不是方法。

4:兩次定義,可是給贊成對象。


 

總結:

此次關於閉包的技術分享,其實更多的是關於js基礎知識點:變量做用域、鏈式做用域、垃圾回收機制、函數聲明、函數表達式、匿名自執行函數等等概念的理解,閉包是一個知識點,很簡單但也不是很好理解,但願對你們有幫助吧。

此次學習參考了不少技術大牛的經驗,再次鳴謝。

相關文章
相關標籤/搜索