]> source.dussan.org Git - jquery.git/commitdiff
Fixes #13571. jQuery.isPlainObject 1.9.x compatibility
authorRick Waldron <waldron.rick@gmail.com>
Wed, 6 Mar 2013 19:42:24 +0000 (14:42 -0500)
committerRick Waldron <waldron.rick@gmail.com>
Wed, 6 Mar 2013 19:42:24 +0000 (14:42 -0500)
Signed-off-by: Rick Waldron <waldron.rick@gmail.com>
src/core.js
test/unit/core.js

index cae3a90e39f5c7ed8aff871fd0f91857512209a5..39e68c4fcebdf70c1ecc17aa44f25fcb0818ea78 100644 (file)
@@ -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 ) {
index 7c840993b6f33c5f2ef6a9a69bad70dee9535639..79367771118199e50dfaa0cf89465d8bfdc3884b 100644 (file)
@@ -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() {