這篇文章要跟大家介紹的內容是關於jQuery中data操作的方法及jQuery的定義,有一定的參考價值,有需要的朋友可以參考一下,希望對你有幫助。
jQuery中有兩個關於data操作的方法
$().data() $.data(elem);
內部其實作都離不開自訂類別Data
Data
Data
在src/data/Data.js
定義,建置時為實例新增expando
屬性,作為唯一標識
function Data() { this.expando = jQuery.expando + Data.uid++; }
在原型上新增了多個方法
Data.prototype = { cache: function(){ ... }, set: function(){ ... }, get: function(){ ... }, access: function(){ ... }, remove: function(){ ... }, hasData: function(){ ... } }
在jq內部,使用cache方法取得快取的資料。傳入一個參數owner,表示要取得快取資料的物件。判斷在owner上是否有expando屬性,如果沒有,說明這個owner是否第一次調用,需要在其初始化快取資料物件。判斷節點的類型,如果是元素節點或document節點或物件時,可以設定快取資料。如果是元素節點或是document節點,直接使用物件字面量來賦值,屬性名稱是expando,值為空物件。如果是物件的話,使用Object.defineProperty
為其定義數據,屬性名稱也是expando,初始化為{},同時屬性描述符可以更改,不可列舉。
Data.prototype.cache
cache: function( owner ) { // Check if the owner object already has a cache // 获取在owner的缓存值 var value = owner[ this.expando ]; // If not, create one if ( !value ) { value = {}; // We can accept data for non-element nodes in modern browsers, // but we should not, see #8335. // Always return an empty object. // 判断owener类型 是否能在其上调用data // 在元素节点或body或对象上可以设置data // 其他节点不设置缓存数据 if ( acceptData( owner ) ) { // If it is a node unlikely to be stringify-ed or looped over // use plain assignment // 此处为owner添加属性 key为Data对象的expando值 建立owner和Data对象之间的连接 // owner是元素节点或body if ( owner.nodeType ) { owner[ this.expando ] = value; // Otherwise secure it in a non-enumerable property // configurable must be true to allow the property to be // deleted when data is removed // owner是对象 // 为owner添加expando属性 初始化为{},同时属性描述符可以更改,不可枚举 } else { Object.defineProperty( owner, this.expando, { value: value, configurable: true } ); } } } return value; }
使用set
來更新快取對象,分為data(key,value)
或data(obj)
兩種呼叫情況,儲存時要將鍵名儲存為駝峰命名法。
Data.prototype.set
set: function( owner, data, value ) { var prop, cache = this.cache( owner ); // Handle: [ owner, key, value ] args // Always use camelCase key (gh-2257) if ( typeof data === "string" ) { cache[ jQuery.camelCase( data ) ] = value; // Handle: [ owner, { properties } ] args } else { // Copy the properties one-by-one to the cache object for ( prop in data ) { cache[ jQuery.camelCase( prop ) ] = data[ prop ]; } } return cache; }
使用get
來取得快取對象,呼叫時有data(key)
和data()
。未指定key時直接傳回整個cache對象,否則傳回cache[key]。鍵名也要轉為駝峰命名。
Data.prototype.get
get: function( owner, key ) { return key === undefined ? this.cache( owner ) : // Always use camelCase key (gh-2257) owner[ this.expando ] && owner[ this.expando ][ jQuery.camelCase( key ) ]; }
對呼叫的方式區分,內部呼叫set
或get
透過參數的數量和型別區分:
key為空時,取得整個cache物件
key型別為string
且value===undefined
對應取得指定值
其他呼叫皆為set
,在 set
內部進行區分
Data.prototype.access
access: function( owner, key, value ) { // In cases where either: // // 1. No key was specified // 2. A string key was specified, but no value provided // // 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 && typeof key === "string" ) && value === undefined ) ) { return this.get( owner, key ); } // When the key is not a string, or both a key and value // are specified, set or extend (existing objects) with either: // // 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
來刪除快取物件屬性,當呼叫時,可以傳入一個string,表示要刪除的鍵名,或是傳入一個保存多個鍵名的string數組。鍵名也要轉為駝峰命名。如果不傳入出參數,則直接刪除掉在owner上的快取資料物件。
Data.prototype.remove
remove: function( owner, key ) { var i, cache = owner[ this.expando ]; if ( cache === undefined ) { return; } if ( key !== undefined ) { // Support array or space separated string of keys if ( Array.isArray( key ) ) { // If key is an array of keys... // We always set camelCase keys, so remove that. key = key.map( jQuery.camelCase ); } else { key = jQuery.camelCase( key ); // If a key with the spaces exists, use it. // Otherwise, create an array by matching non-whitespace key = key in cache ? [ key ] : ( key.match( rnothtmlwhite ) || [] ); } i = key.length; while ( i-- ) { delete cache[ key[ i ] ]; } } // Remove the expando if there's no more data if ( key === undefined || jQuery.isEmptyObject( cache ) ) { // Support: Chrome <=35 - 45 // Webkit & Blink performance suffers when deleting properties // from DOM nodes, so set to undefined instead // https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted) if ( owner.nodeType ) { owner[ this.expando ] = undefined; } else { delete owner[ this.expando ]; } } }
判斷owner上是否有快取資料。
Data.prototype.hasData
hasData: function( owner ) { var cache = owner[ this.expando ]; return cache !== undefined && !jQuery.isEmptyObject( cache ); }
#jQuery方法的定義
##定義後內部類別data #後,在
/src/data.js進行拓展。在jQuery新增了
hasData、
data、
removeData、
_data、
_removeData等方法,在jQuery.fn上新增了
data和
removeData方法。
$.data()時,並無對
set#和
get操作區分,在
Data.prototype.access內部區分set和get。在下方原始碼中,
dataUser和
dataPriv是
Data#實例,分別為快取資料和表示jq物件是否將元素的data屬性加入
dataUser中
// $.data 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.fn#上拓展的方法只有
data和
removeData。在
data內,先將
$().data()和
$().data({k:v})兩個呼叫情況進行處理。如果是第一種情況,則傳回在
this[0]上的快取資料對象,如果是第一次以
$().data()的方式調用,同時也會將元素上的data屬性加入
dataUser中,並更新
dataPriv。如果是
$().data({k:v})的呼叫方式,則遍歷jq對象,為每個節點更新快取資料。其他呼叫方式如
$().data(k)和
$().data(k,v)則呼叫
access進行處理。此處的
access並非
Data.prototype.access。
removeData則遍歷jq對象,刪除在每個節點上的快取資料。
// $().data jQuery.fn.extend( { data: function( key, value ) { var i, name, data, elem = this[ 0 ], // elem为dom对象 attrs = elem && elem.attributes; // 节点上的属性 // Gets all values // $().data() if ( key === undefined ) { if ( this.length ) { data = dataUser.get( elem ); // elem是元素节点,且dataPriv中无hasDataAttrs时执行这个代码块里的代码 // dataPriv上的hasDataAttrs表示elem是否有data-xxx属性 // 初始化dataPriv后花括号内的代码不再执行,即以下的if内的代码只执行一次 if ( elem.nodeType === 1 && !dataPriv.get( elem, "hasDataAttrs" ) ) { i = attrs.length; while ( i-- ) { // Support: IE 11 only // The attrs elements can be null (#14894) // 将elem的data-*-*属性以*-*转为驼峰命名方式的值为键 // 在dataAttr函数内保存到dataUser中 // 所以用$().data可以获取元素的data-*属性 但修改后dom上的属性却不变化 if ( attrs[ i ] ) { name = attrs[ i ].name; // name为data-xxx if ( name.indexOf( "data-" ) === 0 ) { // name为xxx name = jQuery.camelCase( name.slice( 5 ) ); dataAttr( elem, name, data[ name ] ); } } } // 同时将dataPriv的hasDataAttrs属性设置为真,表示已经将元素属性节点上的data属性保存到缓存对象中 dataPriv.set( elem, "hasDataAttrs", true ); } } return data; } // Sets multiple values // $().data(obj) 此处遍历this,即遍历jq对象上所有的节点,并在其设置值 if ( typeof key === "object" ) { return this.each( function() { dataUser.set( this, key ); } ); } // 除了$().data()和$().data({k:v})的其他情况 return access( this, function( value ) { var data; // The calling jQuery object (element matches) is not empty // (and therefore has an element appears at this[ 0 ]) and the // `value` parameter was not undefined. An empty jQuery object // will result in `undefined` for elem = this[ 0 ] which will // throw an exception if an attempt to read a data cache is made. // value undefined说明是获取操作 // 调用$().data(k) if ( elem && value === undefined ) { // Attempt to get data from the cache // The key will always be camelCased in Data // 从dataUser中获取 非undefined时返回 data = dataUser.get( elem, key ); if ( data !== undefined ) { return data; } // Attempt to "discover" the data in // HTML5 custom data-* attrs // dataUser中不存在key,调用dataAttr查找元素的data-*属性 // 如果存在属性,更新dataUser并返回其值 data = dataAttr( elem, key ); if ( data !== undefined ) { return data; } // We tried really hard, but the data doesn't exist. return; } // Set the data... // jq对象长度 >= 1, 调用如$().data(k,v) 遍历jq对象,为每个节点设置缓存数据 this.each( function() { // We always store the camelCased key dataUser.set( this, key, value ); } ); }, null, value, arguments.length > 1, null, true ); }, // 遍历jq对象,删除各个元素上的缓存数据 removeData: function( key ) { return this.each( function() { dataUser.remove( this, key ); } ); } } );
getData用於對元素上的data屬性進行類型轉換,
dataAttr用於取得保存在元素節點上的data屬性,並同時更新
dataUser。要注意的是,以
$().data(k, v)方式呼叫時,如果在快取資料上查找不到屬性,則會呼叫
dataAttr在元素中尋找屬性。
// 属性值是string 进行类型转换 function getData( data ) { if ( data === "true" ) { return true; } if ( data === "false" ) { return false; } if ( data === "null" ) { return null; } // Only convert to a number if it doesn't change the string // data转化成number再转成string后仍严格等于data if ( data === +data + "" ) { return +data; } if ( rbrace.test( data ) ) { return JSON.parse( data ); } return data; } // 获取元素的dataset中的属性,并保存到dataUser中 function dataAttr( elem, key, data ) { var name; // If nothing was found internally, try to fetch any // data from the HTML5 data-* attribute // 此处获取dataset里的值 if ( data === undefined && elem.nodeType === 1 ) { name = "data-" + key.replace( rmultiDash, "-$&" ).toLowerCase(); // 此处将驼峰命名方式的key转化为data-*-* data = elem.getAttribute( name ); if ( typeof data === "string" ) { try { data = getData( data ); } catch ( e ) {} // Make sure we set the data so it isn't changed later // 将元素的data-*属性保存到dataUser中 dataUser.set( elem, key, data ); } else { data = undefined; } } return data; }
JavaScript函數怎麼用?JavaScript函數的屬性和方法的介紹
#以上是jQuery中data操作的方法及jQuery的定義的詳細內容。更多資訊請關注PHP中文網其他相關文章!