From d28cc15be291d9e8686989aee206e34097dea2f6 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Sat, 25 May 2013 01:08:08 -0700 Subject: [PATCH] Ensure `_.isPlainObject` returns `true` for empty objects in older browsers. [closes #283] Former-commit-id: d01d32b1cbd87d08bc8014d07eaa1842e3118a40 --- build.js | 13 +++++-------- lodash.js | 51 +++++++++++++++++++++++++-------------------------- test/test.js | 6 +++++- 3 files changed, 35 insertions(+), 35 deletions(-) diff --git a/build.js b/build.js index aa15dfc2f..de40b7937 100755 --- a/build.js +++ b/build.js @@ -1319,14 +1319,11 @@ source = removeFunction(source, 'isNode'); source = removeSupportProp(source, 'nodeClass'); - // remove `support.nodeClass` from `shimIsPlainObject` - source = source.replace(matchFunction(source, 'shimIsPlainObject'), function(match) { - return match.replace(/\(support\.nodeClass[\s\S]+?\)\)/, 'true'); - }); - - // remove `support.nodeClass` from `_.clone` - source = source.replace(matchFunction(source, 'clone'), function(match) { - return match.replace(/\s*\|\|\s*\(!support\.nodeClass[\s\S]+?\)\)/, ''); + // remove `support.nodeClass` from `_.clone` and `shimIsPlainObject` + _.each(['clone', 'shimIsPlainObject'], function(methodName) { + source = source.replace(matchFunction(source, methodName), function(match) { + return match.replace(/\s*\|\|\s*\(!support\.nodeClass[\s\S]+?\)\)/, ''); + }); }); // remove `support.nodeClass` from `_.isEqual` diff --git a/lodash.js b/lodash.js index 1a1ed7466..ba98b3342 100644 --- a/lodash.js +++ b/lodash.js @@ -1026,34 +1026,33 @@ * @returns {Boolean} Returns `true`, if `value` is a plain object, else `false`. */ function shimIsPlainObject(value) { - // avoid non-objects and false positives for `arguments` objects - var result = false; - if (!(value && toString.call(value) == objectClass) || (!support.argsClass && isArguments(value))) { - return result; - } - // check that the constructor is `Object` (i.e. `Object instanceof Object`) - var ctor = value.constructor; + var ctor, + result; - if (isFunction(ctor) ? ctor instanceof ctor : (support.nodeClass || !isNode(value))) { - // IE < 9 iterates inherited properties before own properties. If the first - // iterated property is an object's own property then there are no inherited - // enumerable properties. - if (support.ownLast) { - forIn(value, function(value, key, object) { - result = hasOwnProperty.call(object, key); - return false; - }); - return result === true; - } - // In most environments an object's own properties are iterated before - // its inherited properties. If the last iterated property is an object's - // own property then there are no inherited enumerable properties. - forIn(value, function(value, key) { - result = key; - }); - return result === false || hasOwnProperty.call(value, result); + // avoid non Object objects, `arguments` objects, and DOM elements + if (!(value && toString.call(value) == objectClass) || + (ctor = value.constructor, isFunction(ctor) && !(ctor instanceof ctor)) || + (!support.argsClass && isArguments(value)) || + (!support.nodeClass && isNode(value))) { + return false; } - return result; + // IE < 9 iterates inherited properties before own properties. If the first + // iterated property is an object's own property then there are no inherited + // enumerable properties. + if (support.ownLast) { + forIn(value, function(value, key, object) { + result = hasOwnProperty.call(object, key); + return false; + }); + return result !== false; + } + // In most environments an object's own properties are iterated before + // its inherited properties. If the last iterated property is an object's + // own property then there are no inherited enumerable properties. + forIn(value, function(value, key) { + result = key; + }); + return result === undefined || hasOwnProperty.call(value, result); } /** diff --git a/test/test.js b/test/test.js index 431d884c6..d50c9ecf4 100644 --- a/test/test.js +++ b/test/test.js @@ -1655,12 +1655,16 @@ } }); + test('should return `true` for empty objects', function() { + strictEqual(_.isPlainObject({}), true); + }); + test('should return `false` for Object objects without a [[Class]] of "Object"', function() { strictEqual(_.isPlainObject(arguments), false); strictEqual(_.isPlainObject(Error), false); strictEqual(_.isPlainObject(Math), false); strictEqual(_.isPlainObject(window), false); - }) + }); }()); /*--------------------------------------------------------------------------*/