jQuery.data( )方法与内存泄漏

5 篇文章 0 订阅
2 篇文章 0 订阅

在jQuery的官方文档中,提示用户这是一个低级的方法,应该用.data()方法来代替。$.data( element, key, value )可以对DOM元素附加任何类型的数据,但应避免循环引用而导致的内存泄漏问题,原文如下:

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:

但对于该方法,存在的问题也不仅于此。在JQUERY FORUM中 ,对该问题作了深入的讨论,robert.katic 提出了一条解决方案。$.data()方法应用到宿主对象上,运行会得到优化,但在本地对像上使用该方法,结果未必尽如人意。一个元素在正常情况下可以使用.remove()方法将其删除,并清除各自的数据。但对于本地对象而言,这是不能彻底删除的,这些相关的数据一直持续到窗口对象关闭。同样,这些问题也存在于event 对象中,因为事件处理器(handlers)也是用该方法来存储的。

那么,要解决该问题最简单的方法是将数据存储到本地对象新增的一个属性之中。即:

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

但是,一旦涉及到继承问题,该方法就无能为力。试看:

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

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

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

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

开始时,存储数据的对象不存在,因此创建一个对象来存储新的值,如图

现在,我们尝试去修改对象childA同样的数据。

对象childA并不存在该数据,因此它沿着原型链向上查找,父对象刚好拥有该数据,其值立即被改写。所以,从parent和childB这两个对象获取“foo”的值,得到的将是“childA value”,而不是“parent value”。

为了避免类似的情况出现,我们用hasOwnProperty来检索自己的数据对象。这样childA的值将不会向上广播到原型链,也就不能继承父对象的值。事实上,避免使用hasOwnProperty来读取数据,也只有个在对象不具有该数据时才返回父对象的值。

另外一种方法是将数据存储到本地对象自身中,但是,它不能返回数据对象,因为该对象不存在,如:

// ...
if ( elem.nodeType ) {
dataObject[ name ] = value;
} else {
elem[ expando +"_" + name ] = value;
}
// ...

robert.katic 推崇第一种方法,并重写了$.data()和$.removeData()方法 .

(function($){
var expando = "jQuery" + (new Date).getTime(),
hasOwnProperty = Object.prototype.hasOwnProperty,
_data = $.data,
_removeData = $.removeData;
$.data = function( obj, name, data ) {
if ( obj.nodeType ) {
return _data( obj, name, data );
}
var thisCache, hasCache = hasOwnProperty.call( obj, expando );
if ( !hasCache && typeof name === "string" && data === undefined ) {
return undefined;
}

if ( typeof name === "object" ) {
obj[ expando ] = $.extend(true, {}, name);

} else if ( !hasCache ) {
obj[ expando ] = {};
}
thisCache = obj[ expando ];
if ( typeof name === "string" ) {
if ( data !== undefined ) {
thisCache[ name ] = data;
}
return thisCache[ name ];
}
return thisCache;
};

$.removeData = function( obj, name ) {
if ( obj.nodeType ) {
return _removeData( obj, name );
}
if ( name ) {
if ( hasOwnProperty.call( obj, expando ) ) {
delete obj[ expando ][ name ];
if ( $.isEmptyObject( obj[expando] ) ) {
delete obj[ expando ];
}
}
} else {
delete obj[ expando ];
}
};
})(jQuery);

jQuery是一个很优秀的库,但是有时也难免会有一些小瑕疵。而这些小瑕疵正是我们在使用时要特别小心。非常感谢robert.katic 为我们详细的分析了该方法的缺陷。

参考资料:http://forum.jquery.com/topic/data-object-and-memory-leak

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值