jquery框架在实现过程中对性能优化也做了很多处理,其中使用缓存就是重要的性能优化手段。
实现原理是从对象属性中取值,如果取值为undefined,则为此对象属性赋值,如果取值不为undefined,则直接返回,这样当在页面多次取对象属性值时,可以直接返回之前设置值,避免重复赋值,从而提高页面性能。如下代码模拟jQeruy实现了缓存方法
function TestCache() {
}
TestCache.prototype = {
cache: function(owner) {
var value = owner["cache"];
if (!value) {
value = {};
owner["cache"] = value;
}
return value;
}
};
使用缓存
var testCache = new TestCache();
var owner = {};
// 第一次从缓存取值,缓存不存在,则初始化
var noCache = testCache.cache(owner);
// 给缓存返回值进行赋值
noCache["name"] = "zhangsan";
noCache["age"] = 28;
noCache["handle"] = function() {
alert(this.name + "---" + this.age);
}; }
// 第二次从缓存取值,直接获取
var useCache = testCache.cache(owner);
useCache.handle();
jQuery缓存实现
function Data() {
this.expando = jQuery.expando + Data.uid++;
}
Data.uid = 1;
Data.prototype = {
...
// 提供缓存方法
cache: function( owner ) {
// 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 ) ) {
return {};
}
// 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 ) {
// 向对象属性赋值,即缓存了value对象
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;
},
// 通过get方法取得缓存对象
get: function( owner, key ) {
return key === undefined ?
this.cache( owner ) :
owner[ this.expando ] && owner[ this.expando ][ key ];
},
...
}
// 实例化Data对象
var dataPriv = new Data();
在jQuery.event.add方法中初始化缓存对象
jQuery.event = {
...
add: function( elem, types, handler, data, selector ) {
// 从缓存中获取对象,如果缓存中不存在,则初始化缓存对象
var elemData = dataPriv.get( elem );
// 以下对缓存对象进行属性增强
if ( !( events = elemData.events ) ) {
events = elemData.events = {};
}
if ( !( eventHandle = elemData.handle ) ) {
eventHandle = elemData.handle = function( e ) {
...
}
}
...
while ( t-- ) {
...
// handleObj is passed to all event handlers
handleObj = jQuery.extend( {
type: type,
origType: origType,
data: data,
handler: handler,
guid: handler.guid,
selector: selector,
needsContext: selector && jQuery.expr.match.needsContext.test( selector ),
namespace: namespaces.join( "." )
}, handleObjIn );
if ( !( handlers = events[ type ] ) ) {
handlers = events[ type ] = [];
handlers.delegateCount = 0;
}
handlers.push( handleObj );
...
}
}
...
}
在jQuery.event.dispatch方法中使用缓存
jQuery.event = {
...
dispatch: function( event ) {
// 取出缓存值,"events"属性是通过jQuery.event.add方法中对缓存对象进行了属性增强而得到
var handlers = ( dataPriv.get( this, "events" ) || {} )[ event.type ] || [],
...
}
...
}