淺析jQuery 3.0中的Data
jQuery 3.0 在6月9日正式發(fā)布了,3.0 也被稱(chēng)為下一代的 jQuery。這個(gè)版本從14年10月開(kāi)始,其中發(fā)布過(guò)一次beta 版(2016/1/14,)和候選版(2016/05/20)。一路走來(lái),頗為不易。
一、Data淺析
jQuery 3.0 中的 Data 是內(nèi)部使用的,定義為一個(gè)“類(lèi)”。一共用它創(chuàng)建了兩個(gè)對(duì)象,dataPriv 和 dataUser。Data 有 1 個(gè)對(duì)象屬性(expando)和類(lèi)屬性(uid),有 6 個(gè)方法,如下
下面分別解讀
1、Data.uid
這是一個(gè)從 1 開(kāi)始用來(lái)自增的數(shù)字。
2、expando
由 jQuery.expando 和 uid 組合而成,它用來(lái)作為元素(如DOM元素)的key,是唯一的。jQuery.expando 的生成如下
jQuery.expando = "jQuery" + ( version + Math.random() ).replace( /\D/g, "" )
即 'jQuery' + (版本號(hào) + 隨機(jī)數(shù)),然后把非數(shù)字的都去掉,比如
"jQuery" + ".." + . == "jQuery..."
去掉非數(shù)字變?yōu)?/p>
jQuery30009423638425146147"
jQuery 3.0 內(nèi)部變量 dataPriv 和 dataUser 生成 expando 如下
jQuery 300 024727210109188635 1 jQuery 300 024727210109188635 2
第三部分是隨機(jī)數(shù),每次刷新都會(huì)變,其它部分的不變。
3、cache
cache 方法會(huì)給 owner 上綁定一個(gè)對(duì)象作為存儲(chǔ),owner 必須滿(mǎn)足 acceptData 的,cache 會(huì)以 this.expando 為線(xiàn)索 key。
owner 有兩種,一中是DOM元素(nodeType為1和9),另一種則是普通的JS對(duì)象。諸如 文本節(jié)點(diǎn)(nodeType=3)、注釋節(jié)點(diǎn)(nodeType=8) 一律不添加。
acceptData 的定義如下
var acceptData = function( owner ) { // Accepts only: // - Node // - Node.ELEMENT_NODE // - Node.DOCUMENT_NODE // - Object // - Any /* jshint -W018 */ return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType ); };
acceptData 在 3.0 中一共有 3 處使用,分別為
Data 類(lèi)的 cache 方法,為私有方法不提供給程序員使用。$.cleanData 方法,清空元素關(guān)聯(lián)的所有緩存數(shù)據(jù)。為公開(kāi)方法,但很少使用。該方法被用在 empty、html、replaceWith、remove 方法中。$().trigger 方法,主動(dòng)派發(fā)事件,為公開(kāi)方法。
如果是 DOM 元素,則直接使用點(diǎn)操作符賦值,如果是普通 JS 對(duì)象則使用 ES5 的 Object.defineProperty 方法,這也是 jQuery 3.0 會(huì)使用新 API 的體現(xiàn)。
// If it is a node unlikely to be stringify-ed or looped over // use plain assignment 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 } else { Object.defineProperty( owner, this.expando, { value: value, configurable: true } ); }
轉(zhuǎn)換成如下代碼
elem['jQuery3000247272101091886351'] = dataObj; var person = {name: 'John', age: 30}; Object.defineProperty( person, 'jQuery3000247272101091886351', { value: dataObj, configurable: true } );
cache 方法就是這樣,傳入 owner,只有第一次會(huì) set ,返回 value (一個(gè)空對(duì)象),之后取到 value 后直接返回。
源碼
cache: function( owner ) { // Check if the owner object already has a cache 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. if ( acceptData( owner ) ) { // If it is a node unlikely to be stringify-ed or looped over // use plain assignment 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 } else { Object.defineProperty( owner, this.expando, { value: value, configurable: true } ); } } } return value; },
4、set
上面的 cache 方法為 owner 建立一個(gè)以 expando 為 key 的空對(duì)象,后面所有的方法都圍繞這個(gè)空對(duì)象來(lái)展開(kāi),這個(gè)空對(duì)象就被稱(chēng)為緩存對(duì)象,后面所有的數(shù)據(jù)都添加到它上面。set 就是給這個(gè)對(duì)象來(lái)添磚加瓦,set 每次都是先取回 cache ,再給其添加新的屬性及數(shù)據(jù)。如果 data 是字符串,則以它為 key 添加,如果是對(duì)象,則遍歷它添加。只需注意一點(diǎn),橫線(xiàn)連接符內(nèi)部會(huì)被轉(zhuǎn)成駝峰格式,這也是為了對(duì) H5 data-xxx 的兼容 。
源碼
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; },
5、get
get 簡(jiǎn)單至極,傳 key 則從 cache 上取回該 key 的值,無(wú)則取回整個(gè) cache。
源碼
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 ) ]; },
6、access
這個(gè)方法即時(shí) getter,也是 setter,如此而已。
getter 條件
key 是 undefined,這時(shí)取整個(gè) cachekey 是字符串且value 是undefined,這是取指定 key 的值
setter 條件
owner、key、value 這三個(gè)參數(shù)都傳
源碼
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; },
7、remove
清空綁定元素(owner)上面的緩存對(duì)象,依然需要先通過(guò) this.expando 拿到 cache,如果傳了 key 則刪除指定key的值(key自身也被刪除)。
當(dāng)然 jQuery API 保持已有的方便性,key 可以為一個(gè)數(shù)組,這樣可以批量刪除多個(gè) key。如果 key 沒(méi)傳則將整個(gè) cache 刪除,這里區(qū)分了 DOM 和普通 JS 對(duì)象,DOM 對(duì)象使用undefined賦值,JS 對(duì)象則使用 delete。
源碼
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 ( jQuery.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( rnotwhite ) || [] ); } 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 ]; } } },
8、hasData
用來(lái)判斷 owner 上是否有緩存數(shù)據(jù),返回 true 或 false。
源碼
hasData: function( owner ) { var cache = owner[ this.expando ]; return cache !== undefined && !jQuery.isEmptyObject( cache ); }
二、Data在jQuery內(nèi)部的使用
以上解讀完了 Data 的所有方法,上面也提到 Data 類(lèi)是在 jQuery 內(nèi)部使用的,一共創(chuàng)建了它的兩個(gè)對(duì)象:dataPriv 和 dataUser。
這兩個(gè)對(duì)象在 3.0.0 中有著明確的分工,dataPriv 可以猜測(cè)到是 “data” 和 “private” 兩個(gè)單詞的組合后簡(jiǎn)寫(xiě)。即 dataPriv 是私有的用來(lái)服務(wù) jQuery 內(nèi)部方法,dataUser 用來(lái)服務(wù)那些公開(kāi)給用戶(hù)使用的方法。
下面看下這兩個(gè)對(duì)象分布在哪些模塊中使用。
完整版點(diǎn)擊展開(kāi)可查看
dataPriv 公共 $.hasData $.cleanData cloneCopyEvent 隊(duì)列 $().queue $()._queueHooks $().promise 動(dòng)畫(huà) $().animate $().stop $().finish showHide 事件 $.event.add $.event.remove $.event.dispatch $.event.trigger 其它 setGlobalEval domManip defaultPrefilter $().toggleClass dataUser 公共 $.hasData $.cleanData cloneCopyEvent 數(shù)據(jù)緩存 $.data $.removeData $().data $().removeData 其它 dataAttr
以上可以看到,除了“公共”,DataPriv 用在了 jQuery 的 隊(duì)列、動(dòng)畫(huà)、事件等模塊;dataUser 用在了數(shù)據(jù)緩存及dataAttr模塊。
“公共” 是指這三個(gè)方法內(nèi)都用到了 dataPriv 和 dataUser
$.hasData(elem)
用來(lái)判斷 elem 上是否綁定了相關(guān)的數(shù)據(jù)緩存,返回 true 和false,只有 dataPriv 和 dataUser 上都沒(méi)有才返回 false
源碼
hasData: function( elem ) { return dataUser.hasData( elem ) || dataPriv.hasData( elem ); },
$.cleanData(elems)
清空 elem 上綁定的所有數(shù)據(jù)緩存,理所當(dāng)然的需要同時(shí)清空 dataPriv 和 dataUser 上的。
注意:雖然這個(gè)方法在公開(kāi)暴露在了 $ 上, 但官網(wǎng)API上卻沒(méi)有該方法的介紹。另使用不當(dāng)會(huì)造成嚴(yán)重后果,比如綁定了事件后(.on),調(diào)用該方法,綁定的事件將全部失效。因?yàn)闀?huì)清空 dataPriv 內(nèi)的所有數(shù)據(jù)。
cloneCopyEvent(src, dest)
這是一個(gè)內(nèi)部方法,$.clone 會(huì)使用到它??寺≡貢r(shí)除了會(huì)克隆node節(jié)點(diǎn)外,綁定在node上的數(shù)據(jù)也會(huì)被克隆過(guò)去。比如
var cloneNode = $.clone(elem);
把 elem 克隆給 cloneNode,此時(shí) elem 上添加的事件 cloneNode 上也會(huì)有。
三、1.x.x 和 2.x.x 的比較
jQuery 1.x 系列 和 2.x 系列的版本對(duì) 數(shù)據(jù)緩存模塊的實(shí)現(xiàn)差異還是很大的。大家可以對(duì)比我11年的這篇文章
1. 緩存的數(shù)據(jù)結(jié)構(gòu)
1.x (直到1.11.2) 緩存都是存儲(chǔ)在 jQuery.cache 上的,2.x(包括3.x) 則使用了一個(gè)內(nèi)部類(lèi) Data 做緩存,其主要用到了兩個(gè)對(duì)象 dataPriv 和 dataUser。很明顯 2.x 做的更好,它所有的緩存數(shù)據(jù)都是私有的,不會(huì)存在被誤寫(xiě)的風(fēng)險(xiǎn),而 1.x 的 jQuery.cache 是公開(kāi)的,如果被誤寫(xiě)(比如某個(gè)同學(xué)想當(dāng)然的給$上添加一個(gè)cache對(duì)象)后果不堪設(shè)想。
2. jQuery._data
看到這個(gè)下劃線(xiàn)就知道是私有的(約定式),在 1.x 中是僅在內(nèi)部使用的,不提供給開(kāi)發(fā)者。以 1.11.2 示例、這個(gè)方法被事件模塊、隊(duì)列模塊、動(dòng)畫(huà)模塊、setGlobalEval、cloneCopyEvent、fixCloneNodeIssues、domManip、showHide、defaultPrefilter、toggleClass 使用。3.x 則使用 dataPriv 和 dataUser 替代,大家可以對(duì)比看看。
(2/3).x 相比 1.x 明顯更優(yōu),dataPriv 和 dataUser 是真正的私有的(封裝的更好,更安全),比起 1.x 約定式的私有 jQuery._data。雖然 3.0.0 還保守的兼容了 jQuery._data,相信過(guò)不了多久的后續(xù)版本就會(huì)剔除。
3. 重構(gòu)
1.x 以 $._data 為中心,以它來(lái)輔助實(shí)現(xiàn)其它 API, (2/3).x 以 dataPriv/dataUser 為中心來(lái)實(shí)現(xiàn)。(2/3).x 將代碼重構(gòu)后提取出了 Data 類(lèi),更加清晰。
以上所述是小編給大家介紹的jQuery 3.0中的Data的全部敘述,希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
相關(guān)文章
tuzhu_req.js 實(shí)現(xiàn)仿百度圖片首頁(yè)效果
這篇文章主要介紹了tuzhu_req.js 實(shí)現(xiàn)仿百度圖片首頁(yè)效果的相關(guān)資料,需要的朋友可以參考下2015-08-08jquery簡(jiǎn)單實(shí)現(xiàn)網(wǎng)頁(yè)層的展開(kāi)與收縮效果
這篇文章主要介紹了jquery簡(jiǎn)單實(shí)現(xiàn)網(wǎng)頁(yè)層的展開(kāi)與收縮效果的方法,涉及jquery中toggle結(jié)合animate方法操作頁(yè)面元素屬性的相關(guān)技巧,非常簡(jiǎn)單實(shí)用,需要的朋友可以參考下2015-08-08formValidator3.3的ajaxValidator一些異常分析
ajaxvalidator是大家問(wèn)的最多的問(wèn)題,修正一個(gè)bug(感謝網(wǎng)友“じ龍峸√”),并把大家最關(guān)心的問(wèn)題,再做一次闡述。2011-07-07jQuery實(shí)現(xiàn)密?;コ鈫?wèn)題解決方案
密保通常都會(huì)有n個(gè)問(wèn)題,讓用戶(hù)選擇其中2、3個(gè),而且都不會(huì)讓用戶(hù)選擇重復(fù)的問(wèn)題。這就要求密?;コ?,具體實(shí)現(xiàn)如下,有此需求的朋友可以參考下2013-08-08jQuery判斷是否存在滾動(dòng)條的簡(jiǎn)單方法
下面小編就為大家?guī)?lái)一篇jQuery判斷是否存在滾動(dòng)條的簡(jiǎn)單方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-09-09jQuery實(shí)現(xiàn)鼠標(biāo)響應(yīng)式淘寶動(dòng)畫(huà)效果示例
這篇文章主要介紹了jQuery實(shí)現(xiàn)鼠標(biāo)響應(yīng)式淘寶動(dòng)畫(huà)效果,涉及jQuery事件響應(yīng)及頁(yè)面元素屬性動(dòng)態(tài)操作相關(guān)使用技巧,需要的朋友可以參考下2018-02-02jQuery簡(jiǎn)單實(shí)現(xiàn)input文本框內(nèi)灰色提示文本效果的方法
這篇文章主要介紹了jQuery簡(jiǎn)單實(shí)現(xiàn)input文本框內(nèi)灰色提示文本效果的方法,涉及jQuery針對(duì)頁(yè)面元素的遍歷與樣式動(dòng)態(tài)操作技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-12-12