JAVA & XML & JAVASCRIPT & AJAX & CSS

          Web 2.0 技術儲備............

            BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
            77 隨筆 :: 17 文章 :: 116 評論 :: 0 Trackbacks
          先把GC和Memory Leak探究暫時放下,牽涉的東西較多。需要逐一進行解釋。
          比如這篇文章就是其中的一個影子——閉包(closure)。
          特別注明:我的翻譯是很爛的...:(,而且并沒有按原文那樣一路譯下來,我只是抽取70%左右并加了一些自己的注釋。
          所以建議能讀懂英文的朋友,可以點擊最下面的鏈接去讀原文。

          閉包的兩個特點:

          1。作為一個函數變量的一個引用 - 當函數返回時,其處于激活狀態。
          2。一個閉包就是當一個函數返回時,一個沒有釋放資源的棧區。

          例1。
          <script type="text/javascript">
          function sayHello2(name) {
          ?var text = 'Hello ' + name; // local variable
          ?var sayAlert = function() { alert(text); }
          ?return sayAlert;
          }
          var sy = sayHello2('never-online');
          sy();
          </script>

          作為一個Javascript程序員,應該明白上面的代碼就是一個函數的引用。如果你還不明白或者不清楚的話,請先了解一些基本的知識,我這里不再敘述。

          上面的代碼為什么是一個閉包?
          因為sayHello2函數里有一個內嵌匿名函數
          sayAlert = function(){ alert(text); }
          在Javascript里。如果你創建了一個內嵌函數(如上例),也就是創建了一個閉包。

          在C或者其它的主流語言中,當一個函數返回后,所有的局部變量將不可訪問,因為它們所在的棧已經被消毀。但在Javascript里,如果你聲明了一個內嵌函數,局部變量將在函數返回后依然可訪問。比如上例中的變量sy,就是引用內嵌函數中的匿名函數function(){ alert(text); },可以把上例改成這樣:
          <script type="text/javascript">
          function sayHello2(name) {
          ?var text = 'Hello ' + name; // local variable
          ?var sayAlert = function() { alert(text); }
          ?return sayAlert;
          }
          var sy = sayHello2('never-online');
          alert(sy.toString());
          </script>
          這里也就與閉包的第二個特點相吻合。

          例2。
          <script type="text/javascript">
          function say667() {
          ?// Local variable that ends up within closure
          ?var num = 666;
          ?var sayAlert = function() { alert(num); }
          ?num++;
          ?return sayAlert;
          }

          var sy = say667();
          sy();
          alert(sy.toString());
          </script>

          上面的代碼中,匿名變量function() { alert(num); }中的num,并不是被拷貝,而是繼續引用外函數定義的局部變量——num中的值,直到外函數say667()返回。

          例3。
          <script type="text/javascript">
          function setupSomeGlobals() {
          ?// Local variable that ends up within closure
          ?var num = 666;
          ?// Store some references to functions as global variables
          ?gAlertNumber = function() { alert(num); }
          ?gIncreaseNumber = function() { num++; }
          ?gSetNumber = function(x) { num = x; }
          }

          </script>
          <button onclick="setupSomeGlobals()">生成 - setupSomeGlobals()</button>
          <button onclick="gAlertNumber()">輸出值 - gAlertNumber()</button>
          <button onclick="gIncreaseNumber()">增加 - gIncreaseNumber()</button>
          <button onclick="gSetNumber(5)">賦值5 - gSetNumber(5)</button>

          上例中,gAlertNumber, gIncreaseNumber, gSetNumber都是同一個閉包的引用,setupSomeGlobals(),因為他們聲明都是通過同一個全局調用——setupSomeGlobals()。
          你可以通過“生成”,“增加”,“賦值”,“輸出值”這三個按扭來查看輸出結果。如果你點擊“生成”按鈕,將創建一個新閉包。也就會重寫gAlertNumber(), gIncreaseNumber(), gSetNumber(5)這三個函數。

          如果理解以上代碼后,看下面的例子:

          例4。
          <script type="text/javascript">
          function buildList(list) {
          ?var result = [];
          ?for (var i = 0; i < list.length; i++) {
          ?var item = 'item' + list[i];
          ?result.push( function() {alert(item + ' ' + list[i])} );
          ?}
          ?return result;
          }

          function testList() {
          ?var fnlist = buildList([1,2,3]);
          ?// using j only to help prevent confusion - could use i
          ?for (var j = 0; j < fnlist.length; j++) {
          ?fnlist[j]();
          ?}
          }

          testList();
          </script>
          運行結果:
          item 3 is undefined
          item 3 is undefined
          item 3 is undefined

          代碼result.push( function() {alert(item + ' ' + list[i])} ),
          使result數組添加了三個匿名函數的引用。這句代碼也可以寫成
          var p = function() {alert(item + ' ' + list[i])};
          result.push(p);

          關于為什么會輸出三次都是 "item 3 is undefined"

          在上面的例子say667()例子中已經解釋過了。
          匿名函數function() {alert(item + ' ' + list[i])}中的list[i]并不是經過拷貝,而是對參數list的一個引用。直到函數buildList()返回為止,也就是說,返回最后一個引用。即遍歷完list(注:list的最大下標應該是2)后,經過i++也就變成了3,這也就是為什么是item 3,而list[3]本身是沒有初始化的,自然也就是undefined了。

          例5。
          <script type="text/javascript">
          function newClosure(someNum, someRef) {
          ?// Local variables that end up within closure
          ?var num = someNum;
          ?var anArray = [1,2,3];
          ?var ref = someRef;
          ?return function(x) {
          ?num += x;
          ?anArray.push(num);
          ?alert('num: ' + num +
          ?'\nanArray ' + anArray.toString() +
          ?'\nref.someVar ' + ref.someVar);
          ?}
          }
          var closure1 = newClosure(40, {someVar:' never-online'})
          var closure2 = newClosure(99, {someVar:' BlueDestiny'})
          closure1(4)
          closure2(3)
          </script>

          在這最后一個例子中,展示如何聲明兩個不同的閉包。
          posted on 2006-10-24 09:42 Web 2.0 技術資源 閱讀(216) 評論(0)  編輯  收藏

          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          主站蜘蛛池模板: 铜山县| 博爱县| 紫阳县| 杨浦区| 铜山县| 连州市| 泾源县| 阿尔山市| 瑞丽市| 昭苏县| 招远市| 微山县| 共和县| 泽库县| 阳春市| 平南县| 五莲县| 牡丹江市| 平泉县| 井陉县| 永胜县| 星子县| 外汇| 西充县| 绩溪县| 宿松县| 威宁| 新丰县| 盖州市| 什邡市| 左云县| 贡嘎县| 苍南县| 温宿县| 霍州市| 崇明县| 厦门市| 武汉市| 津市市| 大荔县| 旬邑县|