Skip to content

Commit e0d3bfa

Browse files
gibson042timmywil
authored andcommitted
Core: Simplify isPlainObject
Fixes gh-2986 Close gh-2998
1 parent 10fc590 commit e0d3bfa

File tree

5 files changed

+37
-23
lines changed

5 files changed

+37
-23
lines changed

src/core.js

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,21 @@
11
define( [
22
"./var/arr",
33
"./var/document",
4+
"./var/getProto",
45
"./var/slice",
56
"./var/concat",
67
"./var/push",
78
"./var/indexOf",
89
"./var/class2type",
910
"./var/toString",
1011
"./var/hasOwn",
12+
"./var/fnToString",
13+
"./var/ObjectFunctionString",
1114
"./var/support",
1215
"./core/DOMEval"
13-
], function( arr, document, slice, concat,
14-
push, indexOf, class2type, toString, hasOwn, support, DOMEval ) {
16+
], function( arr, document, getProto, slice, concat, push, indexOf,
17+
class2type, toString, hasOwn, fnToString, ObjectFunctionString,
18+
support, DOMEval ) {
1519

1620
var
1721
version = "@VERSION",
@@ -225,28 +229,24 @@ jQuery.extend( {
225229
},
226230

227231
isPlainObject: function( obj ) {
228-
var key;
232+
var proto, Ctor;
229233

230-
// Not plain objects:
231-
// - Any object or value whose internal [[Class]] property is not "[object Object]"
232-
// - DOM nodes
233-
// - window
234-
if ( jQuery.type( obj ) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
234+
// Detect obvious negatives
235+
// Use toString instead of jQuery.type to catch host objects
236+
if ( !obj || toString.call( obj ) !== "[object Object]" ) {
235237
return false;
236238
}
237239

238-
// Not own constructor property must be Object
239-
if ( obj.constructor &&
240-
!hasOwn.call( obj, "constructor" ) &&
241-
!hasOwn.call( obj.constructor.prototype || {}, "isPrototypeOf" ) ) {
242-
return false;
243-
}
240+
proto = getProto( obj );
244241

245-
// Own properties are enumerated firstly, so to speed up,
246-
// if last one is own, then all properties are own
247-
for ( key in obj ) {}
242+
// Objects with no prototype (e.g., `Object.create( null )`) are plain
243+
if ( !proto ) {
244+
return true;
245+
}
248246

249-
return key === undefined || hasOwn.call( obj, key );
247+
// Objects with prototype are plain iff they were constructed by a global Object function
248+
Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor;
249+
return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString;
250250
},
251251

252252
isEmptyObject: function( obj ) {

src/var/ObjectFunctionString.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
define( [
2+
"./fnToString"
3+
], function( fnToString ) {
4+
return fnToString.call( Object );
5+
} );

src/var/fnToString.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
define( [
2+
"./hasOwn"
3+
], function( hasOwn ) {
4+
return hasOwn.toString;
5+
} );

src/var/getProto.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
define( function() {
2+
return Object.getPrototypeOf;
3+
} );

test/unit/core.js

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,7 @@ QUnit.test( "type for `Symbol`", function( assert ) {
287287

288288
QUnit.asyncTest( "isPlainObject", function( assert ) {
289289

290-
assert.expect( 22 );
290+
assert.expect( 23 );
291291

292292
var pass, iframe, doc, parentObj, childObj, deep,
293293
fn = function() {};
@@ -300,12 +300,13 @@ QUnit.asyncTest( "isPlainObject", function( assert ) {
300300
assert.ok( jQuery.isPlainObject( { constructor: "foo" } ),
301301
"plain object with primitive constructor property" );
302302

303-
parentObj = { foo: "bar" };
303+
parentObj = {};
304304
childObj = Object.create( parentObj );
305-
306-
assert.ok( !jQuery.isPlainObject( childObj ), "isPlainObject(Object.create({}))" );
305+
assert.ok( !jQuery.isPlainObject( childObj ), "Object.create({})" );
306+
parentObj.foo = "bar";
307+
assert.ok( !jQuery.isPlainObject( childObj ), "Object.create({...})" );
307308
childObj.bar = "foo";
308-
assert.ok( !jQuery.isPlainObject( childObj ), "isPlainObject(Object.create({}))" );
309+
assert.ok( !jQuery.isPlainObject( childObj ), "extend(Object.create({...}), ...)" );
309310

310311
// Not objects shouldn't be matched
311312
assert.ok( !jQuery.isPlainObject( "" ), "string" );

0 commit comments

Comments
 (0)