From 8d1c42296fefc4e79189b6c2d78a8a78fdd9576d Mon Sep 17 00:00:00 2001 From: Rick Waldron Date: Wed, 6 Mar 2013 14:42:24 -0500 Subject: [PATCH 1/2] Fixes #13571. jQuery.isPlainObject 1.9.x compatibility Signed-off-by: Rick Waldron --- src/core.js | 11 ++++++++--- test/unit/core.js | 43 +++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 49 insertions(+), 5 deletions(-) diff --git a/src/core.js b/src/core.js index cae3a90e39..39e68c4fce 100644 --- a/src/core.js +++ b/src/core.js @@ -422,8 +422,11 @@ jQuery.extend({ }, isPlainObject: function( obj ) { + var key; // Not plain objects: // - Any object or value whose internal [[Class]] property is not "[object Object]" + // ...Unless it was a constructor, whose prototype property was paved over by + // by a plain object at its declaration. #13571 // - DOM nodes // - window if ( jQuery.type( obj ) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) { @@ -442,9 +445,11 @@ jQuery.extend({ return false; } - // If the function hasn't returned already, we're confident that - // |obj| is a plain object, created by {} or constructed with new Object - return true; + // Own properties are enumerated firstly, so to speed up, + // if last one is own, then all properties are own. + for ( key in obj ) {} + + return key === undefined || core_hasOwn.call( obj, key ); }, isEmptyObject: function( obj ) { diff --git a/test/unit/core.js b/test/unit/core.js index 7c840993b6..7936777111 100644 --- a/test/unit/core.js +++ b/test/unit/core.js @@ -296,9 +296,9 @@ test("type", function() { }); asyncTest("isPlainObject", function() { - expect(15); + expect(16); - var pass, iframe, doc, + var pass, iframe, doc, c, extended, fn = function() {}; // The use case that we want to match @@ -360,6 +360,45 @@ asyncTest("isPlainObject", function() { } catch(e) { window.iframeDone( Object, "iframes not supported" ); } + + // #13571 + function C() {} + C.prototype = { + x: 1 + }; + c = new C(); + + extended = jQuery.extend( true, {}, { + target: c + }); + + strictEqual( + extended.target, c, + "Instances, whose constructor defined its prototype by assigning a plain object, " + + "will lie about their true identity to preserve a broken user-code expectation" + ); + // + // The test above is broken and tests a broken feature, to support a misinformed + // assumption, as documented here: + // + // http://bugs.jquery.com/ticket/13571#comment:4 + // + // It will not pass if the object being assigned as the prototype + // has no properties: + // + // function C() {} + // C.prototype = {}; + // c = new C(); + + // extended = jQuery.extend( true, {}, { + // target: c + // }); + + // strictEqual( extended.target, c, "Undetectable, will fail every time" ); + // + // The solution is to reset the constructor property of your plain object prototypes. + // + // }); test("isFunction", function() { From 5c82d36f194a854a19f81bebd3ed1a6e7559c811 Mon Sep 17 00:00:00 2001 From: Rick Waldron Date: Wed, 6 Mar 2013 15:11:20 -0500 Subject: [PATCH 2/2] Revert 8d1c42296fefc4e79189b6c2d78a8a78fdd9576d --- src/core.js | 11 +++-------- test/unit/core.js | 43 ++----------------------------------------- 2 files changed, 5 insertions(+), 49 deletions(-) diff --git a/src/core.js b/src/core.js index 39e68c4fce..cae3a90e39 100644 --- a/src/core.js +++ b/src/core.js @@ -422,11 +422,8 @@ jQuery.extend({ }, isPlainObject: function( obj ) { - var key; // Not plain objects: // - Any object or value whose internal [[Class]] property is not "[object Object]" - // ...Unless it was a constructor, whose prototype property was paved over by - // by a plain object at its declaration. #13571 // - DOM nodes // - window if ( jQuery.type( obj ) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) { @@ -445,11 +442,9 @@ jQuery.extend({ return false; } - // Own properties are enumerated firstly, so to speed up, - // if last one is own, then all properties are own. - for ( key in obj ) {} - - return key === undefined || core_hasOwn.call( obj, key ); + // If the function hasn't returned already, we're confident that + // |obj| is a plain object, created by {} or constructed with new Object + return true; }, isEmptyObject: function( obj ) { diff --git a/test/unit/core.js b/test/unit/core.js index 7936777111..7c840993b6 100644 --- a/test/unit/core.js +++ b/test/unit/core.js @@ -296,9 +296,9 @@ test("type", function() { }); asyncTest("isPlainObject", function() { - expect(16); + expect(15); - var pass, iframe, doc, c, extended, + var pass, iframe, doc, fn = function() {}; // The use case that we want to match @@ -360,45 +360,6 @@ asyncTest("isPlainObject", function() { } catch(e) { window.iframeDone( Object, "iframes not supported" ); } - - // #13571 - function C() {} - C.prototype = { - x: 1 - }; - c = new C(); - - extended = jQuery.extend( true, {}, { - target: c - }); - - strictEqual( - extended.target, c, - "Instances, whose constructor defined its prototype by assigning a plain object, " + - "will lie about their true identity to preserve a broken user-code expectation" - ); - // - // The test above is broken and tests a broken feature, to support a misinformed - // assumption, as documented here: - // - // http://bugs.jquery.com/ticket/13571#comment:4 - // - // It will not pass if the object being assigned as the prototype - // has no properties: - // - // function C() {} - // C.prototype = {}; - // c = new C(); - - // extended = jQuery.extend( true, {}, { - // target: c - // }); - - // strictEqual( extended.target, c, "Undetectable, will fail every time" ); - // - // The solution is to reset the constructor property of your plain object prototypes. - // - // }); test("isFunction", function() {