網頁制作poluoluo文章簡介:jQuery.data()方法與內存洩漏.
在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”。
網頁制作poluoluo文章簡介:jQuery.data()方法與內存洩漏.
為了避免類似的情況出現,我們用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
原文:http://www.denisdeng.com/?p=805