日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

深入jQuery中的data()

發布時間:2023/11/27 生活经验 19 豆豆
生活随笔 收集整理的這篇文章主要介紹了 深入jQuery中的data() 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

引入

  data函數在jQuery中看起來很不起眼, 就像沙灘上一顆平凡的沙子, 但仔細一瞅, 卻驚訝的發現data是jQuery中無比重要的一環, 甚至jQuery中各種事件都基于此。

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]] accessorObject.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在該緩存池中不存在對應的緩存對象,則在緩存池中為其創建一個緩存對象,并返回該緩存對象的keyif ( !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 ] = {};}//  返回unlockreturn 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 existedunlock = 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 copiedif ( 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 keysif ( 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 manipulationif ( key in cache ) {name = [ key, camel ];} else {// If a key with the spaces exists, use it.// Otherwise, create an array by matching non-whitespacename = 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;
});
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??

轉載于:https://www.cnblogs.com/MnCu8261/p/6105103.html

總結

以上是生活随笔為你收集整理的深入jQuery中的data()的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。