xml地图|网站地图|网站标签 [设为首页] [加入收藏]

方法与内存泄漏,jQuery对象数据缓存Cache原理及

来源:http://www.ccidsi.com 作者:呼叫中心培训课程 人气:133 发布时间:2019-11-28
摘要:在jQuery的官方文书档案中,提示用户那是一个初级的办法,应该用.data()方法来替代。$.data(element, key, value)可以对DOM元素附加其余项指标数目,但应制止循环引用而诱致的内存泄漏难点,

在jQuery的官方文书档案中,提示用户那是一个初级的办法,应该用.data()方法来替代。$.data( element, key, value )可以对DOM元素附加其余项指标数目,但应制止循环引用而诱致的内存泄漏难点,原作如下:

作者:nuysoft/高云 QQ:47214707 EMail:[email protected]

网络有广大教你怎么利用jQuery.data(..)来完结数据缓存,但有四个客商时时利用的data([key],[value])和jQuery.data(element,[key],[value])大致从未什么文章说精晓它们两的界别,所以小编动用了,研商下分享给大家。

The jQuery.data() method allows us to attach data of any type to DOM elements in a way that is safe from circular references and therefore from memory leaks. We can set several distinct values for a single element and retrieve them later:

声称:本文为原创文章,如需转载,请阐明来源并保存最早的文章链接。

$("").data([key],[value])与jQuery.data(element,[key],[value])的区别
那五个函数都以用来在要素上贮存数据也就日常所说的数据缓存,都回到jQuery对象,那个时候本人分别在运用它俩的时候实在吓本人民代表大会器晚成跳,差别可大了,真是毫无不精善,意气风发用吓生机勃勃跳。看例子先吧,后再依附源代码深入分析。

但对此该办法,存在的标题也不光于此。在JQUE奥迪Q5Y FORUM中 ,对该难题作了深刻的座谈,robert.katic 提议了一条设计方案。$.data()方法应用到宿主对象上,运营会获取优化,但在该地对像上接纳该措施,结果未必快心满意。三个因素在常规状态下得以使用.remove()方法将其除去,并免去各自的数据。但对于本地对象来说,那是不能够通透到底删除的,那么些相关的数目直接不停到窗口对象关闭。相近,这个难题也设有于event 对象中,因为事件微电脑(handlers)也是用该办法来囤积的。

 

Js代码:

那就是说,要缓和该难点最简易的不二秘技是将数据存款和储蓄到地方对象新扩充的多个属性之中。即:

读读写写,不没有错地点请报告自身,多多沟通协作进步,本章的的PDF下载在终极。

复制代码 代码如下:

// ...
if ( elem.nodeType ) {
cache[ id ] = dataObject;
elem[ expando ] = id;
} else {
elem[ expando ] = dataObject;
}
// ...

 

<div id="test2" onclick="test()">test2</div>
<div id="abc3" onclick="test()">test3</div>
<div id="test" onclick="test()">test</div>
<p id="ttt">aaaa</p>
<script>
$(document).ready(function(){
$("#test").click(function(){
alert("JQUERY");
var e=$("div");//定义了两jquery对象
var w=$("div");//e是不对等w的。
//首先利用data([key],[value])用法。
$(e).data("a","aaaa");//分别在e和w上保存Key同样的多寡,
$(w).data("a","wwww");// 看它是或不是会覆盖前面包车型地铁,即使是保留在分裂指标上。
alert($(e).data("a"));//你猜到答案了吗,里输出是wwww;是否有一点点意外?
alert(e===w)//false
alert($(w).data("a"));//这里也是wwww;
//使用jQuery.data(element,[key],[value])来寄放数据。
$.data(e,"b","cccc");//分别在e和w上保存Key同样的多寡,
$.data(w,"b","dddd");// 看它是还是不是会覆盖前面包车型客车,即使是保存在分裂对象上。
alert($.data(e,"b"));//应该你能猜答案吧,输出cccc
alert($.data(w,"b"));//这输出dddd
});
});
</script>

可是,朝气蓬勃旦涉及到持续难题,该方法就不能够。试看:

  1. 数据缓存 Cache
    jQuery提供了jQuery.data()和jQuery.fn.data(),完结对缓存的操作。jQuery.fn.data()内部通过jQuery.data()完成。jQuery.data()有三种用法:

看了上边包车型客车例子是否发掘data([key],[value])与jQuery.data(element,[key],[value])三个平素就不等同了对啊?它们中间究竟有未有提到呢。怎么data([key],[value])会覆盖前边key类似的值吗?

var parent = {};
var childA = Object.create( parent );
var childB = Object.create( parent );

/**

而jQuery.data(element,[key],[value])只假诺绑定到分歧的目的上都不会招致覆盖。是这么呢?这来斟酌下它们的源代码吧。

$.data( parent, "foo", "parent value" );

 * jQuery.data( elem, key, value ) 在内定成分上囤积/增多任性的数量,管理了巡回援用和内部存款和储蓄器泄漏难题

先看jQuery.data(element,[key],[value])源代码。
Js代码:

// This may even be intentional
$.data( childA, "foo" ) // => "parent value"
$.data( childB, "foo" ) // => "parent value"

 * jQuery.data( elem, key ) 再次来到钦赐成分上name钦赐的值

复制代码 代码如下:

// This may NOT be intentional
$.data( childA, "foo", "childA value" );
$.data( parent, "foo" ) // => "childA value"
$.data( childB, "foo" ) // => "childA value"

 * jQuery.data( elem ) 重回全体数码

jQuery.extend({
cache: {},
// Please use with caution
uuid: 0,
// Unique for each copy of jQuery on the page
// Non-digits removed to match rinlinejQuery
expando: "jQuery" ( jQuery.fn.jquery Math.random() ).replace( /D/g, "" ),
....
data: function( elem, name, data, pvt /* Internal Use Only */ ) {
// 是还是不是可以增大数据,不得以则一贯回到
if ( !jQuery.acceptData( elem ) ) {
return;
}
var privateCache, thisCache, ret,
//jQuery.expando那是七个唯后生可畏的字符串,是那介jquery对象产生的时候就生成了。
internalKey = jQuery.expando,
getByName = typeof name === "string",
// 必需分别管理DOM元素和JS对象,因为IE6-7无法垃圾回笼对象跨DOM对象和JS对象开展的引用属性
isNode = elem.nodeType,
// 借使是DOM成分,则运用全局的jQuery.cache
// 假使是JS对象,则平素附加到目的上
cache = isNode ? jQuery.cache : elem,
// Only defining an ID for JS objects if its cache already exists allows
// the code to shortcut on the same path as a DOM node with no cache
id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey,
isEvents = name === "events";
// 制止做越多的不需要专门的学问,当尝试在叁个不曾此外数据的靶子上获取数据时
// 对象未有任何数据,直接重回
if ( (!id || !cache[id] || (!isEvents && !pvt && !cache[id].data)) && getByName && data === undefined ) {
return;
}
// id子虚乌有的话就生成七个
if ( !id ) {
// Only DOM nodes need a new unique ID for each element since their data
// ends up in the global cache
if ( isNode ) {
// 如若是DOM成分则在要素上产生唯生机勃勃的ID 並且以jQuery.expando
//为属性值为id保存在elem成分上,以便未来再根据jQuery.expando来查找ID。
elem[ internalKey ] = id = jQuery.uuid;
} else {
// JS对象则直接接收jQuery.expando,既然是直接附加到指标上,又何供给id呢?
// 制止与此外属性冲突!
id = internalKey;
}
}
//// 当大家试着访问叁个键是还是不是含有值的时候,要是空中楼阁jQuery.cache[id]值,
// 初始化jQuery.cache[id]值 为一个空对象{}
if ( !cache[ id ] ) {
cache[ id ] = {};
if ( !isNode ) {
cache[ id ].toJSON = jQuery.noop;
}
}
// An object can be passed to jQuery.data instead of a key/value pair; this gets
// shallow copied over onto the existing cache
// data是收纳目的和函数,浅拷贝
if ( typeof name === "object" || typeof name === "function" ) {
if ( pvt ) {
cache[ id ] = jQuery.extend( cache[ id ], name );
} else {
cache[ id ].data = jQuery.extend( cache[ id ].data, name );
}
}
/ 存款和储蓄对象,贮存了具备数据的照射对象
privateCache = thisCache = cache[ id ];
// jQuery data() is stored in a separate object inside the object's internal data
// cache in order to avoid key collisions between internal data and user-defined
// data.
// jQuery内部数据存在一个独门的目的(thisCache.data==thisCache[ internalKey ])
//上,为了幸免个中数据和顾客定义数据冲突
if ( !pvt ) {
// 寄存纵走私有多少的目的不设有,则创建三个{}
if ( !thisCache.data ) {
thisCache.data = {};
}
// 使用民用数据对象替换thisCache
thisCache = thisCache.data;
}
// 就算data不是undefined,表示传入了data参数,则存款和储蓄data到name属性上
if ( data !== undefined ) {
// jQuery.camelCase( name )效用是只要传入的是object/function,不做转变,
//唯有传播的name是字符串才会转移。所以最终保存下去的是key/value对;
thisCache[ jQuery.camelCase( name ) ] = data;
}
//从那未来上面包车型地铁代码都以管理data: function( elem, name卡塔尔国data为空,求重返值data的意况了。
if ( isEvents && !thisCache[ name ] ) {
return privateCache.events;
}
// 要是name是字符串,则赶回data
// 假诺不是,则赶回整个存款和储蓄对象
if ( getByName ) {
// First Try to find as-is property data
ret = thisCache[ name ];
// Test for null|undefined property data
if ( ret == null ) {
// Try to find the camelCased property
ret = thisCache[ jQuery.camelCase( name ) ];
}
} else {
ret = thisCache;
}
return ret;
},
............
});

千帆竞发时,存款和储蓄数据的指标空头支票,因而创制八个指标来存款和储蓄新的值,如图

 */  

请看图
皇家赌场游戏 1 
看jQuery.data(element,[key],[value])源代码后得以知道,每叁个element都会有投机的叁个{key:value}对象保存着数量,所以新建的指标即是有key相近它也不会覆盖原本存在的靶子key所对应的value,因为新目的保存是是在另二个{key:value}对象中。

皇家赌场游戏 2

7.1        达成思路
l  写入(援引jQuery.data()接口的多个参数:elem,key,value卡塔尔

接下去要解析data([key],[value])源代码使用到了each(callback),在剖判它前边先看下each(callback)用法和源代码。

前几天,大家品尝去订正对象childA相像的数额。

在协作的DOM成分(elem卡塔尔上附加三个唯风流浪漫ID,在$.cache中增多相同的ID属性,该ID属性的值是一个对象,个中蕴藏了key/value映射。

Js代码:

皇家赌场游戏 3

里面有多少个关键点:

复制代码 代码如下:

  • 共2页:
  • 上一页
  • 1
  • 2
  • 下一页

n  全体数据都存款和储蓄在全局变量$.cache中

<div id="test2" onclick="test()">test2</div>
<div id="abc3" onclick="test()">test3</div>
<div id="test" onclick="test()">test</div>
<p id="ttt">aaaa</p>
<script>
$(document).ready(function(){
$("#test").click(function(){
alert("JQUERY");
var i=0;
$("#abc3").each(function() {
alert( i);//只输出1;因为唯有二个<div id="abc3">
});
alert("----");
var j=0;
$("div").each(function() {
alert( j);//分别出口1,2,3;因为有四个<div>所以循环二次
});
});
});
</script>
今后来看each方法的实际完毕如下:
jQuery.fn = jQuery.prototype = {
each: function( callback, args ) {
return jQuery.each( this, callback, args );
}
}
能够看出它回到的是大局的each方法,而且将本人jQuery对象做为参数给它,全局的each方法的现实性完结如下:
// args 作为个中成员的调用来接收
each: function( object, callback, args ) {
var name, i = 0, length = object.length; // 当object为jQuery对象时,length非空
if ( args ) {
if ( length === undefined ) {
for ( name in object )
if ( callback.apply( object[ name ], args ) === false )
break;
} else
for ( ; i < length; )
if ( callback.apply( object[ i ], args ) === false )
break;
// 以下是客商端程序举行调用
} else {
if ( length === undefined ) {
for ( name in object )
if ( callback.call( object[ name ], name, object[ name ] ) === false )
break;
} else
// i代表索引值,value表示DOM成分
for ( var value = object[0];
i < length && callback.call( value, i, value ) !== false;
value = object[ i] ){}
}
return object;
}

element, key, value )能够对DOM成分附加其余项目标数码,...

n  唯风华正茂ID是二个整型值,发轫为0,调用data接口时自动加风华正茂,生成新的唯后生可畏ID

现行我们关怀下 for ( var value = object[0]; i < length && callback.call( value, i, value ) !== false; value = object[ i] ){} 那句代码;当中object[0]获取jQuery对象中的第一个DOM成分,通过for循环,
获取遍历整个jQuery对象中对应的各种DOM元素,通过callback.call( value,i,value); 将callback的this对象指向value对象,並且传递五个参数,i表示索引值,value代表DOM成分;此中callback是相符于 function(index, elem) { } 的措施。所以就收获 $("").each(function(index, elem){ });
再来看看data([key],[value])的源代码
Js代码:

n  唯意气风发ID附加在以$.expando命名的性质上,$.expando是动态变化的,相同于三个岁月戳,以尽只怕的制止与客户变量冲突

复制代码 代码如下:

l  读取

jQuery.fn.extend({
data: function( key, value ) {
var parts, part, attr, name, l,
elem = this[0],
i = 0,
data = null;
// Gets all values
if ( key === undefined ) {
.....//管理未有Key的景况,这里不是我们要钻探的
return data;
}
// Sets multiple values
if ( typeof key === "object" ) {
return this.each(function() {
jQuery.data( this, key );
});
}
parts = key.split( ".", 2 );
parts[1] = parts[1] ? "." parts[1] : "";
part = parts[1] "!";
return jQuery.access( this, function( value ) {
if ( value === undefined ) {
。。。//这里是一直不value时,是索取重回值的气象,这不是大家讨论
}
parts[1] = value;
//假设小编使用用$("div").data("a","aaa")),上边调用each前的this指的是$("div")这重回的对象,
this.each(function() {//注意了,这里是以每一个卓殊的要素作为左右文来施行多少个函数
var self = jQuery( this );
self.triggerHandler( "setData" part, parts );
//这里在要素上存放数据,本质照旧委托data(element,[key],[value])来做的。
//看眼下有深入分析过了。
//上面data( this, key, value )里的this指的是遍历整个jQuery对象中对应的每一个DOM成分
//$("div")它对应页面中叁个<div>数组。
jQuery.data( this, key, value )<span style="background-color: #ffcc00;">;//那名句会被循环再三施行,也正是保留数据</span>。
//这里就是骨干一句话。但要清楚看上边了它是在each(functipn(){}卡塔尔中的。
self.triggerHandler( "changeData" part, parts );
});
}, null, value, arguments.length > 1, null, false );
},
//在要素上移除存放的数量。具体落到实处如下:
removeData: function( key ) {
return this.each(function() {
jQuery.removeData( this, key );
});
}
});

从相称的DOM成分(elem卡塔 尔(阿拉伯语:قطر‎上取到唯风姿浪漫ID,在$.cache中找到唯一ID对应的对象,再从对应的指标中找到key对应的值

若是对于data([key],[value])的源代码不是很了然,好呢,笔者就用叁个例证来效仿完结它吧。
Js代码:

7.2        验证
上面用代码验证一下(在火狐中用firebug调节和测验卡塔尔国:

复制代码 代码如下:

// 查看存款和储蓄唯生机勃勃ID的属性名

<div id="test2" onclick="test()">test2</div>
<div id="abc3" onclick="test()">test3</div>
<div id="test" onclick="test()">test</div>
<p id="ttt">aaaa</p>
<script>
$(document).ready(function(){
$("#test").click(function(){
alert("JQUERY");
var i=0;
$("#abc3").each(function() {
alert( i);//只输出1;因为只有二个<div id="abc3">
});
alert("----");
var j=1;
$("div").each(function() {//以每三个非常的要素作为左右文来施行这一个函数
$.data(this,"a","wwww");//这里的this就是指$("div"),
//分别遍历每一个天造地设的成分给它们每一种对象{}都保存二个key/value
alert(j );//分别出口1 ,2 ,3 因为有多少个<div>成分
});
alert($("#test").data("a"));//返回wwww,
//是还是不是很惊呀,小编未曾保留在它身上啊,怎么也可以有值,很刚烈是它是查那一个div节点上有未有,
//鲜明是有值了,因为上边给循环境保养存在div这Dom结点上了。
alert($("#test")===$("div"));//false申明两新建的目的不是同三个。
alert($("div").data("a"));//返回wwww,
//这里也是如出风流浪漫辙因为是div节点上都保留了"a"="wwww"这样三个键值对了。
});
});
</script>

$.expando // 返回 "jQuery161013869011191548697"

现在对data([key],[value])与jQuery.data(element,[key]皇家赌场游戏,,[value])都有精晓了呢,假使还是半懂,再回头多看一次,意志地掌握一下。其实表面上特别不均等。但真相上大概有关联的,现在领会原理后就足以请放心地应用了。jQuery.data(element,[key],[value])只把多少绑定到参数element节点上。data([key],[value])
如$("div").data("a","aaaa")它是把数量绑定每一个相配div节点的因素上。
叠合表明下,文中所解析用到的是jquery-1.7.2.js的源代码。下载地址:

// 在body节点上写入数据

...

$('body').data( 'a', 1 )

$('body').data( 'b', 2 )

// 读取body节点的唯大器晚成ID

$('body')[0][ $.expando ] // 返回5

$('body')[0][ "jQuery161013869011191548697" ] // 返回5

// 读取数据

$.cache[5] // 再次来到 Object { a=1, b=2},验证成功!  

7.3        源码深入分析
7.3.1  jQuery.data
// 数据缓存

 

var rbrace = /^(?:{.*}|[.*])$/, // 花括号或方括号

    rmultiDash = /([a-z])([A-Z])/g; // 驼峰写法,大小写之间会被插入破折号

 

jQuery.extend({

    cache: {},

 

    // Please use with caution

    uuid: 0, // 唯后生可畏id种子,DOM成分第叁次调用data接口存款和储蓄数据时,会用uuid 的秘技,生成多个新的唯意气风发id

 

    // Unique for each copy of jQuery on the page

    // Non-digits removed to match rinlinejQuery

    // 页面上jQuery副本的天下无双标志

    // 非数字符号被移除以相称rinlinejQuery

    expando: "jQuery" ( jQuery.fn.jquery Math.random() ).replace( /D/g, "" ),

 

    // The following elements throw uncatchable exceptions if you

    // attempt to add expando properties to them.

    //

    // YunG:

    // 如若尝试在embed、object、applet上附加属性值,将会抛出未捕获的要命

    //

    // embed:

    // embed标签用于广播多少个多媒体对象,包含Flash、音频、录像等

    //

    //

    // object:

    // object成分用于向页面添增添媒体对象,包蕴Flash、音频、录像等。它规定了指标的多寡和参数,甚至可用来显示和操作数据的代码。

    // <object>与</object>之间的公文是替换文本,若是客商的浏览器不帮忙此标签会展现那么些文件。

    // object成分中貌似会含有<param>标签,<param>标签可用来定义播放参数。

    //

    //

    // <embed>和<object>标签的区分:两个都以用来播音多媒体文件的指标,object成分用于IE浏览器,embed成分用于非IE浏览器,为了确认保障宽容性,经常大家同期选用两个因素,浏览器会自动忽视它不补助的价签。同期使用四个成分时,应该把<embed>标签放在<object>标签的里边。

    //

    // applet:

    // 差异情使用

    noData: {

       "embed": true,

       // Ban all objects except for Flash (which handle expandos)

       "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",

       "applet": true

    },

    // 判定二个要素是还是不是有与之提到的数额(通过jQuery.data设置卡塔尔,用在事件管理中

    hasData: function( elem ) {

       // 假设是DOM成分,则从jQuery.cache中读取,关联jQuery.cache和DOM成分的id存款和储蓄在品质jQuery.expando中

       // 若是是非DOM成分,则一向从elem上取,数据存储在 jQuery.expando 属性中

       // elem的质量jQuery.expando,要么值是id,要么值是要存款和储蓄的数额

       // elem被替换为所蕴藏的数据

       elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ];

 

       return !!elem && !isEmptyDataObject( elem );

    },

    /**

     * jQuery.data( elem, key, value ) 在钦赐成分上囤积/加多大肆的多少,管理了循环引用和内部存款和储蓄器泄漏难点

     * jQuery.data( elem, key ) 重临钦赐成分上name内定的值

     * jQuery.data( elem ) 重返全体数目

     */

    /**

     * pvt 私有的,是或不是是内部使用的单身对象,pvt为true时用来事件管理

     */

    data: function( elem, name, data, pvt /* Internal Use Only */ ) {

       // 是或不是足以增大数据,无法则直接重临

       if ( !jQuery.acceptData( elem ) ) {

           return;

       }

 

       var internalKey = jQuery.expando, // 内部key?

           getByName = typeof name === "string", // name必得是字符串?

           thisCache,

 

           // We have to handle DOM nodes and JS objects differently because IE6-7

           // can't GC object references properly across the DOM-JS boundary

           // 必须分别处理DOM成分和JS对象,因为IE6-7不能垃圾回笼对象跨DOM对象和JS对象开展的援用属性

           isNode = elem.nodeType,

 

           // Only DOM nodes need the global jQuery cache; JS object data is

           // attached directly to the object so GC can occur automatically

           // 假使是DOM成分,则采取全局的jQuery.cache(为啥?DOM成分不可能积存非字符串?无法垃圾回收?卡塔尔国

           // 假若是JS对象,则直接附加到指标上

           cache = isNode ? jQuery.cache : elem,

 

           // Only defining an ID for JS objects if its cache already exists allows

           // the code to shortcut on the same path as a DOM node with no cache

           // 假使JS对象的cache已经存在,则供给为JS