国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > JavaScript > 正文

深入學習jQuery中的data()

2019-11-19 18:20:46
字體:
來源:轉載
供稿:網友

data有什么作用?

在我們平時js編碼過程中,我們經常會向DOM元素中添加各種自定義屬性,這樣有一個弊端。

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

  2、當這個js對象發揮完作用后,我們已經用不到他了。這時候按理說應該把這個js變量清空,釋放內存。大家都知道,如果一個js對象不存在任何外在引用的話,解釋器會自動將其在內存中刪除,這也是javascript相對于c++等手動管理內存的程序的優點。

  3、但是這時候問題來了,因為DOM元素引用了這個js對象,盡管這個js對象已經沒有存在的意義了,但是解釋器是不會把他刪除的。如果想要把其刪除,我們可能需要將DOM元素的這個屬性設置為null。

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

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

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

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

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

首先來說一說jQuery中Data實現的大體思路:

  1、首先我們創建一個數據緩存池,這個緩存池專門用來存儲  向 DOM對象或者jQuery對象附加的額外數據。

  2、當我們要向DOM對象或者jQuery對象附加額外數據的時候,我們附加的數據其實是保存于這個緩存池中

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

  4、當我們訪問DOM對象或者jQuery對象的附加數據時,實際上是先取得其附加數據的門牌號,然后找到緩存池中對應門牌號的數據,進行操作。

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

在jQuery中,有一個Data構造函數,每當運行這個構造函數時,就會生成一個實例。

jQuery默認會自動生成兩個Data實例:

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

  var dataUser = new Data()   這個就是服務于用戶了,我們使用data()方法都是對這個實例進行操作。

所有的Data實例都有以下屬性:

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

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

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

來個實例:

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

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

  這個屬性的名稱就是dataUser的expando的值

  這個屬性的值就是門牌號。

總結: data實際上就是對js對象或者DOM對象的額外屬性做了一個集中的管理。對于那些不會產生內存泄漏的額外數據,我們也可以直接向js對象或者DOM對象附加。

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

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是一個jQuery的唯一標示 // 格式是:'jQuery//d*' 也就是'jQuery'+ 多個數字。這里為啥要搞得這么麻煩呢? // 應因為我們可能會創建多個Data對象,為了保證每個Data對象的expando屬性的值不相等,所以這么搞 this.expando = jQuery.expando + Math.random();}Data.uid = 1; // Data函數的屬性,'靜態屬性'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在該緩存池中存在對應的緩存對象,則返回混存對象的key(是一個數字), // 若owner在該緩存池中不存在對應的緩存對象,則在緩存池中為其創建一個緩存對象,并返回該緩存對象的key if ( !Data.accepts( owner ) ) {  return 0; } var descriptor = {},  // Check if the owner object already has a cache key  // 檢查owner對象在該緩存池中是否存在緩存  unlock = owner[ this.expando ]; // 是一個數字,用來作為緩存池中緩存對象的key // If not, create one // 如果沒有,則創建一個 if ( !unlock ) {  unlock = Data.uid++;  // Secure it in a non-enumerable, non-writable property  // 給owner附加一個屬性 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對應的緩存對象已存在 if ( !this.cache[ unlock ] ) {  this.cache[ unlock ] = {}; } // 返回unlock return unlock; }, set: function( owner, data, value ) { // 設置owner對應的緩存對象 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的對應的緩存對象在緩存池中的key(這里的key,是鍵值對中的鍵的意思)  cache = this.cache[ unlock ]; // 獲取owner所對應的緩存對象 // Handle: [ owner, key, value ] args // 根據傳入參數的個數以及類型實現重載 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:是一個對象(可以是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的話就返回整個緩存對象,若指定了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 整個緩存對象 // 2. The data stored at the key 緩存對象中某個鍵的值 // if ( key === undefined || // 沒有指定key或者指定了字符串格式的key,但沒有指定value  ((key && typeof key === "string") && value === undefined) ) {  // 沒有指定key:獲取整個緩存對象  // 指定了字符串格式的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: // 當key不是一個字符串,或者key和value都指定了,就會根據情況進行設置或者擴展 // // 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對應的緩存對象,或者移除緩存對象中的某個鍵值對 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;});

可能會有同學問道:如果我想對dataPriv進行操作該如何?

請看源碼:

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進行操作,而jQuery._data() jQuery._remove()都是對dataPriv進行操作。

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

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

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

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

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對象中的每個DOM元素分別附加數據  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

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者動作能帶來一定的幫助,如果有疑問大家可以留言交流。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 广安市| 九江县| 屯门区| 黔西县| 卢湾区| 中西区| 太仆寺旗| 霍林郭勒市| 巨鹿县| 海林市| 兴仁县| 宝坻区| 湘乡市| 射洪县| 丹棱县| 革吉县| 陆丰市| 菏泽市| 无极县| 五华县| 平泉县| 西充县| 星子县| 德庆县| 巨野县| 开封县| 于田县| 莱阳市| 洞口县| 彩票| 泗水县| 尉犁县| 泽普县| 宣汉县| 河源市| 秦皇岛市| 丹寨县| 洪雅县| 勐海县| 准格尔旗| 澎湖县|