JAVA & XML & JAVASCRIPT & AJAX & CSS

          Web 2.0 技術(shù)儲備............

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

          閉包的兩個特點:

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

          例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程序員,應(yīng)該明白上面的代碼就是一個函數(shù)的引用。如果你還不明白或者不清楚的話,請先了解一些基本的知識,我這里不再敘述。

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

          在C或者其它的主流語言中,當一個函數(shù)返回后,所有的局部變量將不可訪問,因為它們所在的棧已經(jīng)被消毀。但在Javascript里,如果你聲明了一個內(nèi)嵌函數(shù),局部變量將在函數(shù)返回后依然可訪問。比如上例中的變量sy,就是引用內(nèi)嵌函數(shù)中的匿名函數(shù)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,并不是被拷貝,而是繼續(xù)引用外函數(shù)定義的局部變量——num中的值,直到外函數(shù)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(),因為他們聲明都是通過同一個全局調(diào)用——setupSomeGlobals()。
          你可以通過“生成”,“增加”,“賦值”,“輸出值”這三個按扭來查看輸出結(jié)果。如果你點擊“生成”按鈕,將創(chuàng)建一個新閉包。也就會重寫gAlertNumber(), gIncreaseNumber(), gSetNumber(5)這三個函數(shù)。

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

          例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>
          運行結(jié)果:
          item 3 is undefined
          item 3 is undefined
          item 3 is undefined

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

          關(guān)于為什么會輸出三次都是 "item 3 is undefined"

          在上面的例子say667()例子中已經(jīng)解釋過了。
          匿名函數(shù)function() {alert(item + ' ' + list[i])}中的list[i]并不是經(jīng)過拷貝,而是對參數(shù)list的一個引用。直到函數(shù)buildList()返回為止,也就是說,返回最后一個引用。即遍歷完list(注:list的最大下標應(yīng)該是2)后,經(jīng)過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 技術(shù)資源 閱讀(216) 評論(0)  編輯  收藏

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


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 茌平县| 贵阳市| 讷河市| 兴山县| 都安| 罗江县| 温州市| 华阴市| 连南| 阳西县| 稻城县| 马尔康县| 运城市| 灵璧县| 郴州市| 全州县| 富平县| 始兴县| 资源县| 辽源市| 常熟市| 板桥市| 会同县| 喀喇| 双江| 台安县| 罗平县| 怀柔区| 易门县| 康保县| 大渡口区| 资溪县| 海城市| 南漳县| 新龙县| 贡山| 房山区| 广宗县| 章丘市| 丰城市| 南丰县|