aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorRick Waldron <waldron.rick@gmail.com>2013-11-11 13:13:22 -0500
committerTimmy Willison <timmywillisn@gmail.com>2015-03-04 17:26:47 -0500
commitd702b7637a61e1973e08c27b8d8de2ed24a543e2 (patch)
tree5facc46a8a1fd855112e851219c6efc1b2206eb3 /src
parent95fb798980d7e404c413e29e20016db9052e2bf2 (diff)
downloadjquery-d702b7637a61e1973e08c27b8d8de2ed24a543e2.tar.gz
jquery-d702b7637a61e1973e08c27b8d8de2ed24a543e2.zip
Data: move element cache to element[expando]
- avoid explicit data.discard() cleanup calls - explicitly remove the data.events property, only when private data exists - reduces code footprint Fixes gh-1734 Close gh-1428
Diffstat (limited to 'src')
-rw-r--r--src/data/Data.js94
-rw-r--r--src/event.js6
-rw-r--r--src/manipulation.js31
3 files changed, 64 insertions, 67 deletions
diff --git a/src/data/Data.js b/src/data/Data.js
index 7b9ec5b54..ec108e062 100644
--- a/src/data/Data.js
+++ b/src/data/Data.js
@@ -5,15 +5,6 @@ define([
], function( jQuery, rnotwhite ) {
function Data() {
- // Support: Android<4,
- // Old WebKit does not have Object.preventExtensions/freeze method,
- // return new empty object instead with no [[set]] accessor
- Object.defineProperty( this.cache = {}, 0, {
- get: function() {
- return {};
- }
- });
-
this.expando = jQuery.expando + Data.uid++;
}
@@ -21,45 +12,60 @@ Data.uid = 1;
Data.accepts = jQuery.acceptData;
Data.prototype = {
- key: function( owner ) {
- // We can accept data for non-element nodes in modern browsers,
- // but we should not, see #8335.
- // Always return the key for a frozen object.
- if ( !Data.accepts( owner ) ) {
- return 0;
- }
-
- // Check if the owner object already has a cache key
- var unlock = owner[ this.expando ];
- // If not, create one
- if ( !unlock ) {
- unlock = Data.uid++;
+ register: function( owner, initial ) {
+ var descriptor = {},
+ value = initial || {};
+ try {
// If it is a node unlikely to be stringify-ed or looped over
// use plain assignment
if ( owner.nodeType ) {
- owner[ this.expando ] = unlock;
+ owner[ this.expando ] = value;
+
// Otherwise secure it in a non-enumerable, non-writable property
+ // configurability must be true to allow the property to be
+ // deleted with the delete operator
} else {
- Object.defineProperty( owner, this.expando, { value: unlock } );
+ descriptor[ this.expando ] = {
+ value: value,
+ writable: true,
+ configurable: true
+ };
+ Object.defineProperties( owner, descriptor );
}
+
+ // Support: Android < 4
+ // Fallback to a less secure definition
+ } catch ( e ) {
+ descriptor[ this.expando ] = value;
+ jQuery.extend( owner, descriptor );
}
- // Ensure the cache object
- if ( !this.cache[ unlock ] ) {
- this.cache[ unlock ] = {};
+ return owner[ this.expando ];
+ },
+ cache: function( owner, initial ) {
+ // We can accept data for non-element nodes in modern browsers,
+ // but we should not, see #8335.
+ // Always return an empty object.
+ if ( !Data.accepts( owner ) ) {
+ return {};
}
- return unlock;
+ // Check if the owner object already has a cache
+ var cache = owner[ this.expando ];
+
+ // If so, return it
+ if ( cache ) {
+ return cache;
+ }
+
+ // If not, register one
+ return this.register( owner, initial );
},
set: function( owner, data, value ) {
var prop,
- // There may be an unlock assigned to this node,
- // if there is no entry for this "owner", create one inline
- // and set the unlock as though an owner entry had always existed
- unlock = this.key( owner ),
- cache = this.cache[ unlock ];
+ cache = this.cache( owner );
// Handle: [ owner, key, value ] args
if ( typeof data === "string" ) {
@@ -69,7 +75,8 @@ Data.prototype = {
} else {
// Fresh assignments by object are shallow copied
if ( jQuery.isEmptyObject( cache ) ) {
- jQuery.extend( this.cache[ unlock ], data );
+
+ jQuery.extend( cache, data );
// Otherwise, copy the properties one-by-one to the cache object
} else {
for ( prop in data ) {
@@ -80,11 +87,7 @@ Data.prototype = {
return cache;
},
get: function( owner, key ) {
- // Either a valid cache is found, or will be created.
- // New caches will be created and the unlock returned,
- // allowing direct access to the newly created
- // empty data object. A valid owner object must be provided.
- var cache = this.cache[ this.key( owner ) ];
+ var cache = this.cache( owner );
return key === undefined ?
cache : cache[ key ];
@@ -125,11 +128,10 @@ Data.prototype = {
},
remove: function( owner, key ) {
var i, name, camel,
- unlock = this.key( owner ),
- cache = this.cache[ unlock ];
+ cache = this.cache( owner );
if ( key === undefined ) {
- this.cache[ unlock ] = {};
+ this.register( owner );
} else {
// Support array or space separated string of keys
@@ -156,19 +158,19 @@ Data.prototype = {
}
i = name.length;
+
while ( i-- ) {
delete cache[ name[ i ] ];
}
}
},
hasData: function( owner ) {
- return !jQuery.isEmptyObject(
- this.cache[ owner[ this.expando ] ] || {}
- );
+ var cache = owner[ this.expando ];
+ return cache !== undefined && !jQuery.isEmptyObject( cache );
},
discard: function( owner ) {
if ( owner[ this.expando ] ) {
- delete this.cache[ owner[ this.expando ] ];
+ delete owner[ this.expando ];
}
}
};
diff --git a/src/event.js b/src/event.js
index ae0539bb9..4849ef3f0 100644
--- a/src/event.js
+++ b/src/event.js
@@ -216,8 +216,12 @@ jQuery.event = {
// Remove the expando if it's no longer used
if ( jQuery.isEmptyObject( events ) ) {
+ // Normally this should go through the data api
+ // but since event.js owns these properties,
+ // this exception is made for the sake of optimizing
+ // the operation.
delete elemData.handle;
- dataPriv.remove( elem, "events" );
+ delete elemData.events;
}
},
diff --git a/src/manipulation.js b/src/manipulation.js
index 7c9f5049a..be982dc2d 100644
--- a/src/manipulation.js
+++ b/src/manipulation.js
@@ -288,34 +288,25 @@ jQuery.extend({
},
cleanData: function( elems ) {
- var data, elem, type, key,
+ var data, elem, type,
special = jQuery.event.special,
i = 0;
for ( ; (elem = elems[ i ]) !== undefined; i++ ) {
- if ( jQuery.acceptData( elem ) ) {
- key = elem[ dataPriv.expando ];
-
- if ( key && (data = dataPriv.cache[ key ]) ) {
- if ( data.events ) {
- for ( type in data.events ) {
- if ( special[ type ] ) {
- jQuery.event.remove( elem, type );
-
- // This is a shortcut to avoid jQuery.event.remove's overhead
- } else {
- jQuery.removeEvent( elem, type, data.handle );
- }
+ if ( jQuery.acceptData( elem ) && (data = elem[ dataPriv.expando ])) {
+ if ( data.events ) {
+ for ( type in data.events ) {
+ if ( special[ type ] ) {
+ jQuery.event.remove( elem, type );
+
+ // This is a shortcut to avoid jQuery.event.remove's overhead
+ } else {
+ jQuery.removeEvent( elem, type, data.handle );
}
}
- if ( dataPriv.cache[ key ] ) {
- // Discard any remaining `private` data
- delete dataPriv.cache[ key ];
- }
}
+ delete data.events;
}
- // Discard any remaining `user` data
- delete dataUser.cache[ elem[ dataUser.expando ] ];
}
}
});