Core: Simplify isPlainObject

Fixes gh-2986
Close gh-2998
This commit is contained in:
Richard Gibson 2016-03-14 16:46:51 -04:00 committed by Timmy Willison
parent 10fc59007d
commit e0d3bfa770
5 changed files with 37 additions and 23 deletions

View File

@ -1,6 +1,7 @@
define( [ define( [
"./var/arr", "./var/arr",
"./var/document", "./var/document",
"./var/getProto",
"./var/slice", "./var/slice",
"./var/concat", "./var/concat",
"./var/push", "./var/push",
@ -8,10 +9,13 @@ define( [
"./var/class2type", "./var/class2type",
"./var/toString", "./var/toString",
"./var/hasOwn", "./var/hasOwn",
"./var/fnToString",
"./var/ObjectFunctionString",
"./var/support", "./var/support",
"./core/DOMEval" "./core/DOMEval"
], function( arr, document, slice, concat, ], function( arr, document, getProto, slice, concat, push, indexOf,
push, indexOf, class2type, toString, hasOwn, support, DOMEval ) { class2type, toString, hasOwn, fnToString, ObjectFunctionString,
support, DOMEval ) {
var var
version = "@VERSION", version = "@VERSION",
@ -225,28 +229,24 @@ jQuery.extend( {
}, },
isPlainObject: function( obj ) { isPlainObject: function( obj ) {
var key; var proto, Ctor;
// Not plain objects: // Detect obvious negatives
// - Any object or value whose internal [[Class]] property is not "[object Object]" // Use toString instead of jQuery.type to catch host objects
// - DOM nodes if ( !obj || toString.call( obj ) !== "[object Object]" ) {
// - window
if ( jQuery.type( obj ) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
return false; return false;
} }
// Not own constructor property must be Object proto = getProto( obj );
if ( obj.constructor &&
!hasOwn.call( obj, "constructor" ) && // Objects with no prototype (e.g., `Object.create( null )`) are plain
!hasOwn.call( obj.constructor.prototype || {}, "isPrototypeOf" ) ) { if ( !proto ) {
return false; return true;
} }
// Own properties are enumerated firstly, so to speed up, // Objects with prototype are plain iff they were constructed by a global Object function
// if last one is own, then all properties are own Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor;
for ( key in obj ) {} return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString;
return key === undefined || hasOwn.call( obj, key );
}, },
isEmptyObject: function( obj ) { isEmptyObject: function( obj ) {

View File

@ -0,0 +1,5 @@
define( [
"./fnToString"
], function( fnToString ) {
return fnToString.call( Object );
} );

5
src/var/fnToString.js Normal file
View File

@ -0,0 +1,5 @@
define( [
"./hasOwn"
], function( hasOwn ) {
return hasOwn.toString;
} );

3
src/var/getProto.js Normal file
View File

@ -0,0 +1,3 @@
define( function() {
return Object.getPrototypeOf;
} );

View File

@ -287,7 +287,7 @@ QUnit.test( "type for `Symbol`", function( assert ) {
QUnit.asyncTest( "isPlainObject", function( assert ) { QUnit.asyncTest( "isPlainObject", function( assert ) {
assert.expect( 22 ); assert.expect( 23 );
var pass, iframe, doc, parentObj, childObj, deep, var pass, iframe, doc, parentObj, childObj, deep,
fn = function() {}; fn = function() {};
@ -300,12 +300,13 @@ QUnit.asyncTest( "isPlainObject", function( assert ) {
assert.ok( jQuery.isPlainObject( { constructor: "foo" } ), assert.ok( jQuery.isPlainObject( { constructor: "foo" } ),
"plain object with primitive constructor property" ); "plain object with primitive constructor property" );
parentObj = { foo: "bar" }; parentObj = {};
childObj = Object.create( parentObj ); childObj = Object.create( parentObj );
assert.ok( !jQuery.isPlainObject( childObj ), "Object.create({})" );
assert.ok( !jQuery.isPlainObject( childObj ), "isPlainObject(Object.create({}))" ); parentObj.foo = "bar";
assert.ok( !jQuery.isPlainObject( childObj ), "Object.create({...})" );
childObj.bar = "foo"; childObj.bar = "foo";
assert.ok( !jQuery.isPlainObject( childObj ), "isPlainObject(Object.create({}))" ); assert.ok( !jQuery.isPlainObject( childObj ), "extend(Object.create({...}), ...)" );
// Not objects shouldn't be matched // Not objects shouldn't be matched
assert.ok( !jQuery.isPlainObject( "" ), "string" ); assert.ok( !jQuery.isPlainObject( "" ), "string" );