The NoteBook of EricKong

            BlogJava :: 首頁 :: 聯系 :: 聚合  :: 管理
            611 Posts :: 1 Stories :: 190 Comments :: 0 Trackbacks

           

          jQuery片段:

           

          1(function(){  
          2 //這里忽略jQuery所有實現  
          3 }
          )()

           

            半年前初次接觸jQuery的時候,我也像其他人一樣很興奮地想看看源碼是什么樣的。然而,在看到源碼的第一眼,我就迷糊了。為什么只有一個匿名函數又沒看到運行(當然是運行了……),就能有jQuery這么個函數庫了?于是,我抱著疑問來到CSDN。結果相信現在很多人都很清楚了(因為在我之后也不乏來者,呵呵~)。當一個匿名函數被括起來,然后再在后面加一個括號,這個匿名函數就能立即運行起來!真神奇哦!

            嘿嘿!胡鬧到此為止。在這一節,我們碰到的jQuery片段是一組立即運行的匿名函數。而這種用法在論壇上也曾引起過激辯——這段代碼究竟屬不屬于閉包呢?帶著這個疑問,我們從基礎開始,分析每個關鍵要素,尋找屬于自己的答案。(沒錯,自己的答案!在我看來,所有理論只是形式,只要它有利于我們的應用實現,就是可取的——黑貓白貓,抓到老鼠的就是好貓!)

            要說匿名函數,我們首先要由函數本身說起。函數的定義如下:

              函數是將唯一的輸出值賦予給每一輸入的“法則”。

            當然,這只是數學上的定義。但是,在計算機編程語言中,函數的定義也八九不離十。因為,我們都知道,計算機中的函數,也類似數學定義中的描述,它是將輸入的若干數據,經過代碼設定的邏輯操作處理后,返回唯一的輸出的一組代碼組合塊。——當然,特例是,輸入的數據為空或輸出的數據為空,或者兩者都為空。

            下面,我們先初步了解一下和匿名函數相關的概念。

              * 函數聲明(function 語句)

            要使用一個函數,我們就得首先聲明它的存在。而我們最常用的方式就是使用function語句來定義一個函數,如:

          1 function abc(){ // code to process }

             當然,你的函數也可以是帶參數的,甚至是帶返回值的。


          1 function abc(x,y){ return x+y; }


            但是,無論你怎么去定義你的函數,JS解釋器都會把它翻譯成一個Function對象。例如,你在定義上面的其中一個例子的函數號,再輸入如下代碼:


          1 alert(typeof abc);// "function"

            你的瀏覽器就會彈出提示框,提示你abc是一個Function對象。那么Function對象究竟是什么呢?

              * Function 對象

            Function對象是JavaScript里面的固有對象,所有的函數實際上都是一個Function對象。關于這個方面的討論,我們留到下一個專題節。我們先看看,Function對象能不能直接運用構造函數創建一個新的函數呢?答案是肯定的。例如:


          1 var abc = new Function("x","y","return x*y;"); alert(abc(2,3)); // "6"

            相信大家現在對如何聲明一個函數應該是有所了解了。那么什么才是匿名函數呢?

              * 聲明匿名函數

            顧名思義,匿名函數就是沒有實際名字的函數。例如,我們把上面的例子中,函數的名字去掉,再判斷一下他是不是一個函數:

           

          1    alert(typeof function(){});// "function" 
          2    alert(typeof function(x,y){return x+y;});// "function" 
          3    alert(typeof new Function("x","y","return x*y;"))// "function" 

           

            我們可以很容易地看到,它們全都是Function對象,換言之,他們都是函數,但是他們都有一個特點——沒有名字。所以我們把他們稱作“匿名函數”。然而,正因為他們沒有“名字”,我們也沒有辦法找到他們。這就引申了如何去調用一個匿名函數的問題了。

              * 匿名函數的調用

            要調用一個函數,我們必須要有方法定位它,引用它。所以,我們會需要幫它找一個名字。例如:


          1 var abc=function(x,y){ return x+y; } alert(abc(2,3)); // "5"

            上面的操作其實就等于換個方式去定義函數,這種用法是我們比較頻繁遇到的。例如我們在設定一個DOM元素事件處理函數的時候,我們通常都不會為他們定名字,而是賦予它的對應事件引用一個匿名函數。

            對匿名函數的調用其實還有一種做法,也就是我們看到的jQuery片段——使用()將匿名函數括起來,然后后面再加一對小括號(包含參數列表)。我們再看一下以下例子:


          alert((function(x,y){return x+y;})(2,3));// "5" 
          alert((new Function("x","y","return x*y;"))(2,3));// "6" 

            很多人或許會奇怪,為什么這種方法能成功調用呢?覺得這個應用奇怪的人就看一下我以下這段解釋吧。

            大家知道小括號的作用嗎?小括號能把我們的表達式組合分塊,并且每一塊,也就是每一對小括號,都有一個返回值。這個返回值實際上也就是小括號中表達式的返回值。所以,當我們用一對小括號把匿名函數括起來的時候,實際上小括號對返回的,就是一個匿名函數的Function對象。因此,小括號對加上匿名函數就如同有名字的函數般被我們取得它的引用位置了。所以如果在這個引用變量后面再加上參數列表,就會實現普通函數的調用形式。

            不知道以上的文字表述大家能不能看明白,如果還是理解不了的話,再看一下以下的代碼試試吧。


          1  var abc=function(x,y){return x+y;};// 把匿名函數對象賦給abc 
          2  // abc的constructor就和匿名函數的 constructor一樣了。也就是說,兩個函數的實現是一樣的。 
          3  alert((abc).constructor==(function(x,y){return x+y;}).constructor); 

            PS:constructor是指創建對象的函數。也就是函數對象所代表的函數體。

            總之,將其(被小括號包含的匿名函數)理解為括號表達式返回的函數對象,然后就可以對這個函數對象作正常的參數列表調用了。(前面這里犯了個錯誤,只有函數表達式還是不能直接調用函數的,去掉匿名函數括號必須要伴隨將表達式賦值。也就是(function(){alert(1)})()應該是與 a=function(){alert(1)}()等價,不能連a=都去掉。)

              * 閉包

             閉包是什么?閉包是指某種程序語言中的代碼塊允許一級函數存在并且在一級函數中所定義的自由變量能不被釋放,直到一級函數被釋放前,一級函數外也能應用這些未釋放的自由變量。

            怎樣?看得一頭冒汗吧……沒事,我也是(雖然是我是了解的,只是表達能力的問題)。讓我們換個更加簡單的方法說明:閉包,其實是一種語言特性,它是指的是程序設計語言中,允許將函數看作對象,然后能像在對象中的操作搬在函數中定義實例(局部)變量,而這些變量能在函數中保存到函數的實例對象銷毀為止,其它代碼塊能通過某種方式獲取這些實例(局部)變量的值并進行應用擴展。

            不知道這么再解釋后會否更加清晰,如果還是不明白,那么我們再簡化一下:閉包,其實就是指程序語言中能讓代碼調用已運行的函數中所定義的局部變量。

            現在我們看一個例子:


           



             
          var abc=function(y){ 
             
          var x=y;// 這個是局部變量 
             return function(){ 
                alert(x
          ++);// 就是這里調用了閉包特性中的一級函數局部變量的x,并對它進行操作 
                alert(y--);// 引用的參數變量也是自由變量 
              }
          }(
          5);// 初始化 
             abc();// "5" "5" 
             abc();// "6" "4" 
             abc();// "7" "3" 
             alert(x);// 報錯!“x”未定義! 

            看到這里,你能判斷究竟jQuery的那個代碼片段是否閉包了嗎?

            以我的理解來說吧。是否應用了閉包特性,必須確定該段代碼有沒有最重要的要素:未銷毀的局部變量。那么很顯然,沒有任何實現的匿名函數不可能應用了閉包特性。但如果匿名函數里面有實現呢?那也還得確定它的實現中有沒有用到那些未銷毀的局部變量。所以如果問你那個開篇中的jQuery代碼片段是應用了JS里的什么特性?那么它只是匿名函數與匿名函數的調用而已。但是,它隱含了閉包的特性,并且隨時可以實現閉包應用。因為JS天生就是有這個特性的!(這只是我的理解,我也想知道你的理解,歡迎交流!關于閉包,有機會還是獨立再開一個專題吧!)

          posted on 2010-05-18 09:15 Eric_jiang 閱讀(528) 評論(0)  編輯  收藏 所屬分類: JavaScript
          主站蜘蛛池模板: 丽江市| 荣成市| 临澧县| 喜德县| 五大连池市| 罗江县| 凤阳县| 白玉县| 贡嘎县| 读书| 疏勒县| 科技| 武川县| 巢湖市| 鄂尔多斯市| 泽库县| 达孜县| 郧西县| 松原市| 阿拉善左旗| 张家港市| 宁乡县| 汪清县| 镇沅| 县级市| 云梦县| 静海县| 永川市| 台北县| 芜湖县| 鲁甸县| 唐海县| 文登市| 江口县| 汉中市| 偏关县| 淮北市| 桐乡市| 高密市| 武汉市| 大英县|