<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      Ruby's Louvre

      每天學習一點點算法

      導航

      jQuery最核心的基礎設施之一——數據緩存模塊進化史

      數據緩存系統最早應該是jQuery1.2引入的,那時它的事件系統完成照搬DE大神的addEvent.js,而addEvent在實現有個缺憾,它把事件的回調都放到EventTarget之上,這會引發循環引用,如果EventTarget是window對象,又會引發全局污染。有了數據緩存系統,除了規避這兩個風險外,我們還可以有效地保存不同方法產生的中間變量,而這些變量會對另一個模塊的方法有用,解耦方法間的依賴。對于jQuery來說,它的事件克隆乃至后來的列隊實現都是離不開緩存系統。

      jQuery1.2 在core模塊新增了兩個靜態方法, data與removeData。data不用說,與jQuery其他方法一樣,讀寫結合。jQuery的緩存系統是把所有數據都放$.cache之上,然后為每個要使用緩存系統的元素節點,文檔對象與window對象分配一個UUID。UUID的屬性名為一個隨機的自定義屬性,"jQuery" + (new Date()).getTime(), 值為整數,從零遞增。但UUID總要附于一個對象上,如果那個對象是window,豈不是全局污染嗎,因此jQuery內部判定它是window對象時,映射為一個叫windowData的空對象,然后UUID加在它之上。有了UUID,我們在首次訪問緩存系統時,會在$.cache對象開辟一個空對象(緩存體),用于放置與目標對象有關的東西。這有點像銀行開戶了,UUID的值就是存折。removeData則會刪掉不再需要保存數據,如果到最后,數據刪清光了,它也沒有任何鍵值對,成為空對象,jQuery就會從$.cache中刪掉此對象,并從目標對象移除UUID。

      //jQuery1.2.3
      var expando = "jQuery" + (new Date()).getTime(), uuid = 0, windowData = {};
      jQuery.extend({
          cache: {},
          data: function( elem, name, data ) {
              elem = elem == window ? windowData :   elem;//對window對象做特別處理
              var id = elem[ expando ];
              if ( !id ) //如果沒有UUID則新設一個
                  id = elem[ expando ] = ++uuid;
              //如果沒有在$.cache中開戶,則先開戶
              if ( name && !jQuery.cache[ id ] )
                  jQuery.cache[ id ] = {};
      
              // 第三個參數不為undefined時,為寫操作
              if ( data != undefined )
                  jQuery.cache[ id ][ name ] = data;
              //如果只有一個參數,則返回緩存對象,兩個參數則返回目標數據
              return name ?  jQuery.cache[ id ][ name ] :   id;
          },
      
          removeData: function( elem, name ) {
              elem = elem == window ? windowData :   elem;
              var id = elem[ expando ];
              if ( name ) {//移除目標數據
                  if ( jQuery.cache[ id ] ) {
                      delete jQuery.cache[ id ][ name ];
                      name = "";
      
                      for ( name in jQuery.cache[ id ] )
                          break;
                      //遍歷緩存體,如果不為空,那name會被改寫,如果沒有被改寫,則!name 為true,
                      //從而引發再次調用此方法,但這次是只傳一個參數,移除緩存體,
                      if ( !name )
                          jQuery.removeData( elem );
                  }
              } else {
                  //移除UUID,但IE下對元素使用delete會拋錯
                  try {
                      delete elem[ expando ];
                  } catch(e){
                      if ( elem.removeAttribute )
                          elem.removeAttribute( expando );
                  }//注銷賬戶
                  delete jQuery.cache[ id ];
              }
          }
      })
      

      jQuery在1.2.3中添加了兩個同名的原型方法data與removeData,目的是方便鏈式操作與集化操作。并在data中添加getData, setData的自定義事件的觸發邏輯。

      1.3中,數據緩存系統終于獨立成一個模塊data.js(內部開發時的劃分),并添加了兩組方法,命名空間上的queue與dequeue,原型上的queue與dequeue。queue的目的很明顯,就是緩存一組數據,為動畫模塊服務。dequeue是從一組數據中刪掉一個。

        //jQuery1.3
        jQuery.extend({
            queue: function( elem, type, data ) {
                if ( elem ){
                    type = (type || "fx") + "queue";
                    var q = jQuery.data( elem, type );
                    if ( !q || jQuery.isArray(data) )//確保儲存的是一個數組
                        q = jQuery.data( elem, type, jQuery.makeArray(data) );
                    else if( data )//然后往這個數據加東西
                        q.push( data );
                }
                return q;
            },
            dequeue: function( elem, type ){
                var queue = jQuery.queue( elem, type ),
                fn = queue.shift();//然后刪掉一個,早期它是放置動畫的回調,刪掉它就call一下,
                // 但沒有做是否為函數的判定,估計也沒有寫到文檔中,為內部使用
                if( !type || type === "fx" )
                    fn = queue[0];
                if( fn !== undefined )
                    fn.call(elem);
            }
        })
      

      fx模塊animate方法的調用示例:

        
        //each是并行處理多個動畫,queue是一個接一個處理多個動畫
        this[ optall.queue === false ? "each" : "queue" ](function(){ /*略*/})
      

      在元素上添加自定義屬性,還會引發一個問題。如果我們對這個元素進行拷貝,就會將此屬性也會復制過去,導致兩個元素都有相同的UUID值,出現數據被錯誤操作的情況。jQuery早期的復制節點實現非常簡單,如果元素的cloneNode方法不會復制事件就使用cloneNode,否則使用元素的outerHTML,或父節點的innerHTML,用clean方法解析一個新元素出來。但outerHTML與innerHTML都會顯式屬性寫在里面,因此需要用正則把它們清除掉。

        //jQuery1.3.2 core.js clone方法
        var ret = this.map(function(){
            if ( !jQuery.support.noCloneEvent && !jQuery.isXMLDoc(this) ) {
                var html = this.outerHTML;
                if ( !html ) {
                    var div = this.ownerDocument.createElement("div");
                    div.appendChild( this.cloneNode(true) );
                    html = div.innerHTML;
                }
        
                return jQuery.clean([html.replace(/ jQuery\d+="(?:\d+|null)"/g, "").replace(/^\s*/, "")])[0];
            } else
                return this.cloneNode(true);
        });
      

      jQuery1.4發現IE如果對于object, ember, applet這三個古老的用于接入外部資源的標簽可能會拋錯。由于舊式IE的元素節點只是COM的包裝,一旦引入資源后,它就會變成那種資源的實例,而它們會有嚴格的訪問控制,不能像普通的JS對象那樣隨意添加成員。于是jQuery便一刀換,但凡是這三種標簽,就不為它緩存數據。jQuery弄了一個叫noData的hash,用于檢測元素節點的標簽。

        noData: {
            "embed": true,
            "object": true,
            "applet": true
        },
        //代碼防御        
        if ( elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()] ) {
            return;
        }
      

      jQuery1.4還對$.data進行改進,允許第二個參數為對象,方便儲存多個數據。UUID對應的自定義屬性expando 也放進命名空間之下了。queue與dequeue方法被剝離成一個新模塊。

        

      jQuery1.43帶來三項改進。

      首先是添加changeData自定義方法。不過這套方法沒有什么銷量,只是產品經理的自戀吧。

        

      檢測元素節點是否支持添加自定義屬性的邏輯被獨立成一個叫acceptData的方法。因為jQuery團隊發現當object標簽加載的flash資源,它還是可以添加自定義屬性的,于是決定對這種情況網開一面。IE在加載flash時,需要對object指定一個叫classId的屬性,值為clsid:D27CDB6E-AE6D-11cf-96B8-444553540000,因此檢測邏輯就變得非常復雜,由于data, removeData都要用到,獨立出來有效節省比特。

      HTML5對人們隨便添加自定義屬性的行為做出回應,新增一種叫"data-*"的緩存機制。當用戶設置的屬性以"data-"開頭,它們會被保存到元素節點的dataset對象上。這就導致人們可能用HTML5方便緩存數據,也可能用jQuery的緩存系統保存數據,那么data方法就變得有點不中用了。于是jQuery在原型上的data做了增強,當用戶第一次訪問此元素節點,會遍歷它所有"data-"開頭的自定義屬性(為了照顧舊式IE,不能直接遍歷dataset),把它們放到jQuery的緩存體中。那么當用戶取數據時,會先從緩存系統中,沒有再使用setAttribute訪問"data-"自定義屬性。但HTML5的緩存系統非常弱,只能保存字符串(這當然是出于循環引用的考量),于是jQuery會將它們還原為各種數據類型,如"null",, "false", "true"變成null, false, true, 符合數字格式的字符串會轉換成數字,如果它是以"{"開頭"}"結尾則嘗試轉成一個對象。

        //jQuery1.43 $.fn.data
        rbrace = /^(?:\{.*\}|\[.*\])$/;
        if ( data === undefined && this.length ) {
            data = jQuery.data( this[0], key );
            if ( data === undefined && this[0].nodeType === 1 ) {
                data = this[0].getAttribute( "data-" + key );
        
                if ( typeof data === "string" ) {
                    try {
                        data = data === "true" ? true :
                            data === "false" ? false :
                            data === "null" ? null :
                            !jQuery.isNaN( data ) ? parseFloat( data ) :
                            rbrace.test( data ) ? jQuery.parseJSON( data ) :
                            data;
                    } catch( e ) {}
        
                } else {
                    data = undefined;
                }
            }
        }
      

      jQuery1.5也帶來三項改進。當時jQuery已經在1.42打敗Prototype.js,如日中天,馬太效應,用戶量暴增。它的重點改為提升性能,進入fix bug階段(用戶多,相當于免費的測試員就越多,測試覆蓋面就越大)。

      改進expando,原來是基于時間截,現在是版本號加隨機數。因此用戶可能在一個頁面引入多個版本的jQuery。

      是否有此數據的邏輯被抽出成一個hasData方法,處理HTML5的"data-*"屬性也被抽出成一個私有方法dataAttr。它們都是為了邏輯顯得更清晰。dataAttr使用JSON.parse,由于這個JSON可能是JSON2.js引入的,而JSON2.js有個非常糟糕的地方,就是為一系列原生類型添加了toJSON方法,導致for in 循環判定是否為空對象出錯。jQuery被逼搞了個isEmptyDataObject方法做處理。

      jQuery的數據緩存系統本來就是為事件系統服務而分化出來的,到后來,它是內部眾多模塊的基礎設施。換言之,它內部會儲存許多框架用戶的變量(系統數據),但一旦它公開到文檔中,用戶也會使用data保存他們務業中使用的數據(用戶數據)。以前,用戶小,變量名沖突的可能性比較少,加之jQuery為這些系統數據精挑了一些不常用的名字,__class__, __change__或加個后綴什么的,沒有收到什么投訴。當jQuery成為世界級的著名框架后,用戶數據名干掉系統數據名,導致事件系統或其他什么模塊癱瘓就時有發生。jQuery開始對緩存體進行改造,原來就是一個對象,什么數據都往里面拋?,F在它就這個緩存體內開辟一個子對象,鍵名為隨機的jQuery.expando值,如果是系統數據就存到里面去。但events系統數據為了向前兼容起見,還是直接放到緩存體之上。至于,如何區分是系統數據,非常簡單,直接在data方法添加第四個參數,真值時為系統數據。removeData時也相應提供第三個參數,用于刪除系統數據。還新設了一個_data方法,專門用于操作系統數據。下面就是緩存體的結構圖:

        
      var cache = {
           jQuery14312343254:{/*放置系統數據*/}
           events: {/"放置事件名與它對應的回調列表"/}
           /*這里放置用戶數據*/
      }
      

      jQuery1.7對緩存體做了改進,系統變量變放置data對象中,為此判定緩存體為空也要做相應的改進,現在要跳過toJSON與data。新結構如下:

      var cache = {
           data:{/*放置用戶數據*/}
           /*這里放置系統數據*/
      }
      

      jQuery1.8曾添加一個叫deleteIds的數組,用于重用UUID。UUID的值從1.8起不用jQuery.uuid的了,改用jQuery.guid遞增生成。重大的改進在jQuery1.83后,操作數據的實現被抽出為私有方法,命名空間與原型上的方法只是一個代理,并分成兩組方法,操作用戶數據的data, removeData,操作系統數據的_data,_removeData。現在光是緩存系統就是一個龐大家族了。

      說到底,數據緩存就是在目標對象與緩存體間建立一對一的關系,然后在緩存體上操作數據,復雜度都集在前者。而在一個普通JS對象進行增刪改查某屬性從來沒有難度,用戶怎么也玩不出花招。從軟件設計原則上看,這也是最好的結果(吻合KISS原則與職責單一則)。

      如何使用?

      
      
      //實例方法
      $(node).data("xxx","yyy")//寫方法,一次寫入一個
      $(node).data({//一次寫入多個
         "aaa":1,
         "bbb":2
      })
      //靜態方法
      $.data(node,"ccc",3)
      $._data(node,"ccc",3)//由于是放在不同對象上,因此不會覆蓋上面的cc
      
      $(node).data("xxx");//讀方法
      
      $.data(node, "xxx")
      $._data(node, "ccc")
      
      $.removeData(node, "xxx")
      $._removeData(node, "ccc")
        
      
      

      posted on 2012-11-19 07:58  司徒正美  閱讀(10658)  評論(25)    收藏  舉報

      主站蜘蛛池模板: 宫西光有码视频中文字幕| 玩弄美艳馊子高潮无码| 国产又爽又黄的激情视频| 国产精品XXXX国产喷水| 国产美女高潮流白浆视频| 欧美成人h精品网站| 国产成人综合在线女婷五月99播放 | 亚洲欧美高清在线精品一区二区| 麻豆国产成人AV在线播放| 唐人社视频呦一区二区| 亚洲2017天堂色无码| 国产麻传媒精品国产av| 国产精品无码不卡在线播放| 樱桃视频影院在线播放| 亚洲色一色噜一噜噜噜| 夜夜夜高潮夜夜爽夜夜爰爰| 天堂影院一区二区三区四区 | 国产h视频在线观看| 强插少妇视频一区二区三区 | 韩国无码AV片午夜福利| 秋霞人妻无码中文字幕| 天堂а√8在线最新版在线| 日韩本精品一区二区三区| 国产精品自拍午夜福利| 亚洲国产精品特色大片观看完整版 | 国产中文字幕在线一区| 国产呦交精品免费视频| 亚洲精中文字幕二区三区| 人妻有码av中文字幕久久琪| AV最新高清无码专区| 熟女亚洲综合精品伊人久久| 一面膜上边一面膜下边视频| 国产无码高清视频不卡| 熟女精品国产一区二区三区| 亚洲高清免费在线观看| 成人国产乱对白在线观看| 亚洲欧洲av一区二区| 熟妇的奶头又大又长奶水视频| 国产精品久久一区二区三区| 亚洲精品综合一区二区在线| 色噜噜一区二区三区|