欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

深入學(xué)習(xí)jQuery中的data()

 更新時(shí)間:2016年12月22日 08:20:08   作者:MnCu  
大家應(yīng)該都會(huì)有這樣一種感覺,data函數(shù)在jQuery中看起來很不起眼, 就像沙灘上一顆平凡的沙子, 但仔細(xì)一瞅, 卻驚訝的發(fā)現(xiàn)data是jQuery中無比重要的一環(huán), 甚至jQuery中各種事件都基于此。下面就來詳細(xì)深入的學(xué)習(xí)下jQuery中的data(),感興趣的朋友們可以參考借鑒。

data有什么作用?

在我們平時(shí)js編碼過程中,我們經(jīng)常會(huì)向DOM元素中添加各種自定義屬性,這樣有一個(gè)弊端。

  1、假設(shè)我們在DOM元素中添加了一個(gè)屬性,這個(gè)屬性指向了某個(gè)js對象。 dom1.ele = jsObj

  2、當(dāng)這個(gè)js對象發(fā)揮完作用后,我們已經(jīng)用不到他了。這時(shí)候按理說應(yīng)該把這個(gè)js變量清空,釋放內(nèi)存。大家都知道,如果一個(gè)js對象不存在任何外在引用的話,解釋器會(huì)自動(dòng)將其在內(nèi)存中刪除,這也是javascript相對于c++等手動(dòng)管理內(nèi)存的程序的優(yōu)點(diǎn)。

  3、但是這時(shí)候問題來了,因?yàn)镈OM元素引用了這個(gè)js對象,盡管這個(gè)js對象已經(jīng)沒有存在的意義了,但是解釋器是不會(huì)把他刪除的。如果想要把其刪除,我們可能需要將DOM元素的這個(gè)屬性設(shè)置為null。

  4、我們編寫了這么多的代碼,哪里能把 每個(gè)js對象是不是被DOM元素引用了都記住啊?

  5、而且,假如DOM元素與js對象之間相互循環(huán)引用,根本就無法刪除! 這就是內(nèi)存泄漏

  6、所以,為了避免這種情況的發(fā)生,我們要盡量避免 引用數(shù)據(jù)(這里的引用數(shù)據(jù)可以說是javascript對象) 直接依附在DOM對象上。

  7、data就是用來搞定以上問題的方法。

data是如何搞定以上問題的?

首先來說一說jQuery中Data實(shí)現(xiàn)的大體思路:

  1、首先我們創(chuàng)建一個(gè)數(shù)據(jù)緩存池,這個(gè)緩存池專門用來存儲  向 DOM對象或者jQuery對象附加的額外數(shù)據(jù)。

  2、當(dāng)我們要向DOM對象或者jQuery對象附加額外數(shù)據(jù)的時(shí)候,我們附加的數(shù)據(jù)其實(shí)是保存于這個(gè)緩存池中

  3、DOM對象或者jQuery對象生成一個(gè)額外屬性,這個(gè)屬性保存了 附加數(shù)據(jù)在緩存池中的‘門牌號'(位置或者索引)

  4、當(dāng)我們訪問DOM對象或者jQuery對象的附加數(shù)據(jù)時(shí),實(shí)際上是先取得其附加數(shù)據(jù)的門牌號,然后找到緩存池中對應(yīng)門牌號的數(shù)據(jù),進(jìn)行操作。

大體思路講完,那么來分析一下具體思路:

在jQuery中,有一個(gè)Data構(gòu)造函數(shù),每當(dāng)運(yùn)行這個(gè)構(gòu)造函數(shù)時(shí),就會(huì)生成一個(gè)實(shí)例。

jQuery默認(rèn)會(huì)自動(dòng)生成兩個(gè)Data實(shí)例:

  var dataPriv = new Data()   jQuery私有的,我們盡量不要對這個(gè)實(shí)例進(jìn)行操作。

  var dataUser = new Data()   這個(gè)就是服務(wù)于用戶了,我們使用data()方法都是對這個(gè)實(shí)例進(jìn)行操作。

所有的Data實(shí)例都有以下屬性:

  expando:  值為字符串類型,每個(gè)Data實(shí)例的expando屬性的值都不相同,用來區(qū)分不同的Data實(shí)例,類似于id的作用,expando的值就是上文中的額外屬性。

  uid:   這就是上文中的門牌號,初始為1,隨著不同對象的附加數(shù)據(jù)的加入,自增長。

  cache : 一個(gè)對象 {} ,這就是緩存池了。

來個(gè)實(shí)例:

$(document.body).data('aaa', 'value-aaa')
console.dir(document.body)

body對象有一個(gè)名為jquer210023......的額外屬性,

  這個(gè)屬性的名稱就是dataUser的expando的值

  這個(gè)屬性的值就是門牌號。

總結(jié): data實(shí)際上就是對js對象或者DOM對象的額外屬性做了一個(gè)集中的管理。對于那些不會(huì)產(chǎn)生內(nèi)存泄漏的額外數(shù)據(jù),我們也可以直接向js對象或者DOM對象附加。

好,理清楚上面的關(guān)系后,我們再來看一下源碼:

define([
 "../core",
 "../var/rnotwhite",
 "./accepts"
], function( jQuery, rnotwhite ) {

function Data() {
 // Support: Android<4,
 // Old WebKit does not have Object.preventExtensions/freeze method,
 // return new empty object instead with no [[set]] accessor
 Object.defineProperty( this.cache = {}, 0, {
 get: function() {
  return {};
 }
 });
 // jQuery.expando = "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ) expando是一個(gè)jQuery的唯一標(biāo)示
 // 格式是:'jQuery\\d*' 也就是'jQuery'+ 多個(gè)數(shù)字。這里為啥要搞得這么麻煩呢?
 // 應(yīng)因?yàn)槲覀兛赡軙?huì)創(chuàng)建多個(gè)Data對象,為了保證每個(gè)Data對象的expando屬性的值不相等,所以這么搞
 this.expando = jQuery.expando + Math.random();
}

Data.uid = 1; // Data函數(shù)的屬性,'靜態(tài)屬性'
Data.accepts = jQuery.acceptData;

Data.prototype = {
 key: function( owner ) {
 // We can accept data for non-element nodes in modern browsers,
 // but we should not, see #8335.
 // Always return the key for a frozen object.
 // 若owner在該緩存池中存在對應(yīng)的緩存對象,則返回混存對象的key(是一個(gè)數(shù)字),
 // 若owner在該緩存池中不存在對應(yīng)的緩存對象,則在緩存池中為其創(chuàng)建一個(gè)緩存對象,并返回該緩存對象的key
 if ( !Data.accepts( owner ) ) {
  return 0;
 }

 var descriptor = {},
  // Check if the owner object already has a cache key
  // 檢查owner對象在該緩存池中是否存在緩存
  unlock = owner[ this.expando ]; // 是一個(gè)數(shù)字,用來作為緩存池中緩存對象的key

 // If not, create one
 // 如果沒有,則創(chuàng)建一個(gè)
 if ( !unlock ) {
  unlock = Data.uid++;

  // Secure it in a non-enumerable, non-writable property
  // 給owner附加一個(gè)屬性 owner[this.expando] = unlock ,并且該屬性不能被枚舉,
  try {
  descriptor[ this.expando ] = { value: unlock };
  Object.defineProperties( owner, descriptor );

  // Support: Android<4
  // Fallback to a less secure definition
  } catch ( e ) {
  descriptor[ this.expando ] = unlock;
  jQuery.extend( owner, descriptor );
  }
 }

 // Ensure the cache object
 // 確保owner對應(yīng)的緩存對象已存在
 if ( !this.cache[ unlock ] ) {
  this.cache[ unlock ] = {};
 }
 // 返回unlock
 return unlock;
 },
 set: function( owner, data, value ) {
 // 設(shè)置owner對應(yīng)的緩存對象
 var prop,
  // There may be an unlock assigned to this node,
  // if there is no entry for this "owner", create one inline
  // and set the unlock as though an owner entry had always existed
  unlock = this.key( owner ), // 獲取owner的對應(yīng)的緩存對象在緩存池中的key(這里的key,是鍵值對中的鍵的意思)
  cache = this.cache[ unlock ]; // 獲取owner所對應(yīng)的緩存對象

 // Handle: [ owner, key, value ] args
 // 根據(jù)傳入?yún)?shù)的個(gè)數(shù)以及類型實(shí)現(xiàn)重載
 if ( typeof data === "string" ) {
  cache[ data ] = value;

 // Handle: [ owner, { properties } ] args
 } else {
  // Fresh assignments by object are shallow copied
  if ( jQuery.isEmptyObject( cache ) ) {
  jQuery.extend( this.cache[ unlock ], data );
  // Otherwise, copy the properties one-by-one to the cache object
  } else {
  for ( prop in data ) {
   cache[ prop ] = data[ prop ];
  }
  }
 }
 // 返回緩存對象
 return cache;
 },
 get: function( owner, key ) {
 // 獲取owner對象的名為key的屬性值
 // owner:是一個(gè)對象(可以是jQuery對象也可以是DOM對象) key: 屬性名
 // Either a valid cache is found, or will be created.
 // New caches will be created and the unlock returned,
 // allowing direct access to the newly created
 // empty data object. A valid owner object must be provided.

 var cache = this.cache[ this.key( owner ) ]; // owner的緩存對象

 return key === undefined ? cache : cache[ key ]; // 沒指定key的話就返回整個(gè)緩存對象,若指定了key則返回在該緩存對象的key屬性的值
 },
 access: function( owner, key, value ) {
 var stored;
 // In cases where either:
 //
 // 1. No key was specified 沒有指定key
 // 2. A string key was specified, but no value provided 指定了字符串格式的key,但沒有指定value
 //
 // Take the "read" path and allow the get method to determine
 // which value to return, respectively either:
 //
 // 1. The entire cache object 整個(gè)緩存對象
 // 2. The data stored at the key 緩存對象中某個(gè)鍵的值
 //
 if ( key === undefined || // 沒有指定key或者指定了字符串格式的key,但沒有指定value
  ((key && typeof key === "string") && value === undefined) ) {

  // 沒有指定key:獲取整個(gè)緩存對象
  // 指定了字符串格式的key,但沒有指定value: 獲取緩存對象中key的值
  stored = this.get( owner, key );


  return stored !== undefined ?
  stored : this.get( owner, jQuery.camelCase(key) );
 }

 // [*]When the key is not a string, or both a key and value
 // are specified, set or extend (existing objects) with either:
 // 當(dāng)key不是一個(gè)字符串,或者key和value都指定了,就會(huì)根據(jù)情況進(jìn)行設(shè)置或者擴(kuò)展
 //
 // 1. An object of properties
 // 2. A key and value
 //
 this.set( owner, key, value );

 // Since the "set" path can have two possible entry points
 // return the expected data based on which path was taken[*]
 return value !== undefined ? value : key;
 },
 remove: function( owner, key ) {
 // 清空owner對應(yīng)的緩存對象,或者移除緩存對象中的某個(gè)鍵值對
 var i, name, camel,
  unlock = this.key( owner ),
  cache = this.cache[ unlock ];
 // 如果沒有指定key,則清空緩存對象
 if ( key === undefined ) {
  this.cache[ unlock ] = {};

 } else {
  // Support array or space separated string of keys
  if ( jQuery.isArray( key ) ) {
  // If "name" is an array of keys...
  // When data is initially created, via ("key", "val") signature,
  // keys will be converted to camelCase.
  // Since there is no way to tell _how_ a key was added, remove
  // both plain key and camelCase key. #12786
  // This will only penalize the array argument path.
  name = key.concat( key.map( jQuery.camelCase ) );
  } else {
  camel = jQuery.camelCase( key );
  // Try the string as a key before any manipulation
  if ( key in cache ) {
   name = [ key, camel ];
  } else {
   // If a key with the spaces exists, use it.
   // Otherwise, create an array by matching non-whitespace
   name = camel;
   name = name in cache ?
   [ name ] : ( name.match( rnotwhite ) || [] );
  }
  }

  i = name.length;
  while ( i-- ) {
  delete cache[ name[ i ] ];
  }
 }
 },
 hasData: function( owner ) {
 // 檢查owner在該緩存池中是否存在緩存對象
 return !jQuery.isEmptyObject(
  this.cache[ owner[ this.expando ] ] || {}
 );
 },
 discard: function( owner ) {
 if ( owner[ this.expando ] ) {
  delete this.cache[ owner[ this.expando ] ];
 }
 }
};

return Data;
});

可能會(huì)有同學(xué)問道:如果我想對dataPriv進(jìn)行操作該如何?

請看源碼:

jQuery.extend({
 hasData: function( elem ) {
 return dataUser.hasData( elem ) || dataPriv.hasData( elem );
 },

 data: function( elem, name, data ) {
 return dataUser.access( elem, name, data );
 },

 removeData: function( elem, name ) {
 dataUser.remove( elem, name );
 },

 // TODO: Now that all calls to _data and _removeData have been replaced
 // with direct calls to dataPriv methods, these can be deprecated.
 _data: function( elem, name, data ) {
 return dataPriv.access( elem, name, data );
 },

 _removeData: function( elem, name ) {
 dataPriv.remove( elem, name );
 }
});

通過源碼,我們可以看出:

jQuery.data() jQuery.remove()都是對dataUser進(jìn)行操作,而jQuery._data() jQuery._remove()都是對dataPriv進(jìn)行操作。

理解jQuery.data(ele,name,data) 與 jQuery().data(key,value)的不同。

  通過上面的源碼,我們可以看到jQuery.data(ele,name,data)是對ele元素附加數(shù)據(jù)。

  而jQuery().data(key,value)則會(huì)為jQuery對象中的所有DOM對象分別附加數(shù)據(jù)

來看源碼(刪減了部分):

jQuery.fn.extend({
 data: function( key, value ) {
 var i, name, data,
  elem = this[ 0 ],
  attrs = elem && elem.attributes;return access( this, function( value ) {
  var data,
  camelKey = jQuery.camelCase( key );

// 從這里可以看出,為jQuery對象中的每個(gè)DOM元素分別附加數(shù)據(jù)
  this.each(function() {
  // First, attempt to store a copy or reference of any
  // data that might've been store with a camelCased key.
  var data = dataUser.get( this, camelKey );

  // For HTML5 data-* attribute interop, we have to
  // store property names with dashes in a camelCase form.
  // This might not apply to all properties...*
  dataUser.set( this, camelKey, value );

  // *... In the case of properties that might _actually_
  // have dashes, we need to also store a copy of that
  // unchanged property.
  if ( key.indexOf("-") !== -1 && data !== undefined ) {
   dataUser.set( this, key, value );
  }
  });
 }, null, value, arguments.length > 1, null, true );
 },

 removeData: function( key ) {
 return this.each(function() {
  dataUser.remove( this, key );
 });
 }
});

上文中的所有源碼:為jQuery.1.12

總結(jié)

以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者動(dòng)作能帶來一定的幫助,如果有疑問大家可以留言交流。

相關(guān)文章

最新評論