Data: avoid using delete on DOM nodes

Closes gh-2479
This commit is contained in:
Jason Bedard 2015-07-18 11:27:11 -07:00 committed by Michał Gołębiowski
parent d4def22e4c
commit 0e982433eb
5 changed files with 46 additions and 12 deletions

View File

@ -20,13 +20,12 @@ Data.prototype = {
if ( owner.nodeType ) {
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
// 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,
writable: true,
configurable: true
} );
}
@ -144,7 +143,16 @@ Data.prototype = {
// Remove the expando if there's no more data
if ( key === undefined || jQuery.isEmptyObject( cache ) ) {
delete owner[ this.expando ];
// Support: Chrome <= 35-45+
// Webkit & Blink performance suffers when deleting properties
// from DOM nodes, so set to undefined instead
// https://code.google.com/p/chromium/issues/detail?id=378607
if ( owner.nodeType ) {
owner[ this.expando ] = undefined;
} else {
delete owner[ this.expando ];
}
}
},
hasData: function( owner ) {

View File

@ -290,10 +290,16 @@ jQuery.extend( {
}
}
}
delete elem[ dataPriv.expando ];
// Support: Chrome <= 35-45+
// Assign undefined instead of using delete, see Data#remove
elem[ dataPriv.expando ] = undefined;
}
if ( elem[ dataUser.expando ] ) {
delete elem[ dataUser.expando ];
// Support: Chrome <= 35-45+
// Assign undefined instead of using delete, see Data#remove
elem[ dataUser.expando ] = undefined;
}
}
}

View File

@ -867,7 +867,7 @@ testIframeWithCallback(
);
QUnit.test( "Check that the expando is removed when there's no more data", function( assert ) {
assert.expect( 1 );
assert.expect( 2 );
var key,
div = jQuery( "<div/>" );
@ -877,6 +877,23 @@ QUnit.test( "Check that the expando is removed when there's no more data", funct
// Make sure the expando is gone
for ( key in div[ 0 ] ) {
if ( /^jQuery/.test( key ) ) {
assert.strictEqual( div[ 0 ][ key ], undefined, "Expando was not removed when there was no more data" );
}
}
});
QUnit.test( "Check that the expando is removed when there's no more data on non-nodes", function( assert ) {
assert.expect( 1 );
var key,
obj = jQuery( {key: 42} );
obj.data( "some", "data" );
assert.equal( obj.data( "some" ), "data", "Data is added" );
obj.removeData( "some" );
// Make sure the expando is gone
for ( key in obj[ 0 ] ) {
if ( /^jQuery/.test( key ) ) {
assert.ok( false, "Expando was not removed when there was no more data" );
}

View File

@ -2702,7 +2702,7 @@ QUnit.test( "Inline event result is returned (#13993)", function( assert ) {
} );
QUnit.test( ".off() removes the expando when there's no more data", function( assert ) {
assert.expect( 1 );
assert.expect( 2 );
var key,
div = jQuery( "<div/>" ).appendTo( "#qunit-fixture" );
@ -2717,7 +2717,10 @@ QUnit.test( ".off() removes the expando when there's no more data", function( as
// Make sure the expando is gone
for ( key in div[ 0 ] ) {
if ( /^jQuery/.test( key ) ) {
assert.ok( false, "Expando was not removed when there was no more data" );
assert.strictEqual(
div[ 0 ][ key ], undefined,
"Expando was not removed when there was no more data"
);
}
}
} );

View File

@ -2086,7 +2086,7 @@ QUnit.test( "jQuery.cleanData eliminates all private data (gh-2127)", function(
} );
QUnit.test( "jQuery.cleanData eliminates all public data", function( assert ) {
assert.expect( 2 );
assert.expect( 3 );
var key,
div = jQuery( "<div/>" );
@ -2100,7 +2100,7 @@ QUnit.test( "jQuery.cleanData eliminates all public data", function( assert ) {
// Make sure the expando is gone
for ( key in div[ 0 ] ) {
if ( /^jQuery/.test( key ) ) {
assert.ok( false, "Expando was not removed when there was no more data" );
assert.strictEqual( div[ 0 ][ key ], undefined, "Expando was not removed when there was no more data" );
}
}
} );