From f9b5d6644d16ced3281d4593b5e50fc407664d31 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Sun, 10 Mar 2013 04:13:34 -0700 Subject: [PATCH] Ensure `_.isPlainObject` returns `false` for objects without a `[[Class]]` of "Object". Former-commit-id: ce034f55733cd1929f09bf80e4a461c6e1502d1b --- build.js | 20 ++++++++++++++------ dist/lodash.compat.js | 6 +++--- dist/lodash.js | 6 +++--- dist/lodash.underscore.js | 2 +- lodash.js | 6 +++--- test/test.js | 7 +++++++ 6 files changed, 31 insertions(+), 16 deletions(-) diff --git a/build.js b/build.js index 964225622..aa3673b2d 100755 --- a/build.js +++ b/build.js @@ -1090,6 +1090,13 @@ return match.replace(/\s*\(support\.argsClass *\?([^:]+):.+?\)\)/g, '$1'); }); + // remove `support.argsClass` from `_.isPlainObject` + _.each(['shimIsPlainObject', 'isPlainObject'], function(methodName) { + source = source.replace(matchFunction(source, methodName), function(match) { + return match.replace(/\s*\|\|\s*\(!support\.argsClass[\s\S]+?\)\)/, ''); + }); + }); + return source; } @@ -1114,7 +1121,7 @@ source = source.replace(getIteratorTemplate(source), function(match) { return match .replace(/(?: *\/\/.*\n)* *["'] *(?:<% *)?if *\(support\.enumPrototypes *(?:&&|\))[\s\S]+?<% *} *(?:%>|["']).+/g, '') - .replace(/support\.enumPrototypes *\|\|\s*/g, ''); + .replace(/support\.enumPrototypes\s*\|\|\s*/g, ''); }); return source; @@ -1137,12 +1144,12 @@ // remove `support.nodeClass` from `_.clone` source = source.replace(matchFunction(source, 'clone'), function(match) { - return match.replace(/ *\|\|\s*\(!support\.nodeClass[\s\S]+?\)\)/, ''); + return match.replace(/\s*\|\|\s*\(!support\.nodeClass[\s\S]+?\)\)/, ''); }); // remove `support.nodeClass` from `_.isEqual` source = source.replace(matchFunction(source, 'isEqual'), function(match) { - return match.replace(/ *\|\|\s*\(!support\.nodeClass[\s\S]+?\)\)\)/, ''); + return match.replace(/\s*\|\|\s*\(!support\.nodeClass[\s\S]+?\)\)\)/, ''); }); return source; @@ -1169,7 +1176,7 @@ source = source.replace(getIteratorTemplate(source), function(match) { return match .replace(/(?: *\/\/.*\n)*( *["'] *)<% *} *else *if *\(support\.nonEnumArgs[\s\S]+?(\1<% *} *%>.+)/, '$2') - .replace(/ *\|\|\s*support\.nonEnumArgs/, ''); + .replace(/\s*\|\|\s*support\.nonEnumArgs/, ''); }); return source; @@ -1710,6 +1717,7 @@ if (isModern) { dependencyMap.isEmpty = _.without(dependencyMap.isEmpty, 'isArguments'); dependencyMap.isEqual = _.without(dependencyMap.isEqual, 'isArguments'); + dependencyMap.isPlainObject = _.without(dependencyMap.isPlainObject, 'isArguments'); dependencyMap.keys = _.without(dependencyMap.keys, 'isArguments'); dependencyMap.reduceRight = _.without(dependencyMap.reduceRight, 'isString'); } @@ -2357,7 +2365,7 @@ // remove native `Array.isArray` branch in `_.isArray` source = source.replace(matchFunction(source, 'isArray'), function(match) { - return match.replace(/nativeIsArray * \|\|\s*/, ''); + return match.replace(/nativeIsArray\s*\|\|\s*/, ''); }); // replace `_.keys` with `shimKeys` @@ -2509,7 +2517,7 @@ // minor cleanup snippet = snippet - .replace(/obj *\|\|\s*\(obj *= *{}\);/, '') + .replace(/obj\s*\|\|\s*\(obj *= *{}\);/, '') .replace(/var __p = '';\s*__p \+=/, 'var __p ='); // remove comments, including sourceURLs diff --git a/dist/lodash.compat.js b/dist/lodash.compat.js index edd5486ad..2c8651223 100644 --- a/dist/lodash.compat.js +++ b/dist/lodash.compat.js @@ -1005,7 +1005,7 @@ function shimIsPlainObject(value) { // avoid non-objects and false positives for `arguments` objects var result = false; - if (!(value && typeof value == 'object') || isArguments(value)) { + if (!(value && toString.call(value) == objectClass) || (!support.argsClass && isArguments(value))) { return result; } // check that the constructor is `Object` (i.e. `Object instanceof Object`) @@ -1838,14 +1838,14 @@ * // => true */ var isPlainObject = !getPrototypeOf ? shimIsPlainObject : function(value) { - if (!(value && typeof value == 'object')) { + if (!(value && toString.call(value) == objectClass) || (!support.argsClass && isArguments(value))) { return false; } var valueOf = value.valueOf, objProto = typeof valueOf == 'function' && (objProto = getPrototypeOf(valueOf)) && getPrototypeOf(objProto); return objProto - ? value == objProto || (getPrototypeOf(value) == objProto && !isArguments(value)) + ? (value == objProto || getPrototypeOf(value) == objProto) : shimIsPlainObject(value); }; diff --git a/dist/lodash.js b/dist/lodash.js index cfa8e4cac..cafc994d5 100644 --- a/dist/lodash.js +++ b/dist/lodash.js @@ -841,7 +841,7 @@ function shimIsPlainObject(value) { // avoid non-objects and false positives for `arguments` objects var result = false; - if (!(value && typeof value == 'object') || isArguments(value)) { + if (!(value && toString.call(value) == objectClass)) { return result; } // check that the constructor is `Object` (i.e. `Object instanceof Object`) @@ -1657,14 +1657,14 @@ * // => true */ var isPlainObject = function(value) { - if (!(value && typeof value == 'object')) { + if (!(value && toString.call(value) == objectClass)) { return false; } var valueOf = value.valueOf, objProto = typeof valueOf == 'function' && (objProto = getPrototypeOf(valueOf)) && getPrototypeOf(objProto); return objProto - ? value == objProto || (getPrototypeOf(value) == objProto && !isArguments(value)) + ? (value == objProto || getPrototypeOf(value) == objProto) : shimIsPlainObject(value); }; diff --git a/dist/lodash.underscore.js b/dist/lodash.underscore.js index 29330653b..d5c850b12 100644 --- a/dist/lodash.underscore.js +++ b/dist/lodash.underscore.js @@ -656,7 +656,7 @@ function shimIsPlainObject(value) { // avoid non-objects and false positives for `arguments` objects var result = false; - if (!(value && typeof value == 'object') || isArguments(value)) { + if (!(value && toString.call(value) == objectClass)) { return result; } // check that the constructor is `Object` (i.e. `Object instanceof Object`) diff --git a/lodash.js b/lodash.js index 61f1d3d07..617c6226f 100644 --- a/lodash.js +++ b/lodash.js @@ -1016,7 +1016,7 @@ function shimIsPlainObject(value) { // avoid non-objects and false positives for `arguments` objects var result = false; - if (!(value && typeof value == 'object') || isArguments(value)) { + if (!(value && toString.call(value) == objectClass) || (!support.argsClass && isArguments(value))) { return result; } // check that the constructor is `Object` (i.e. `Object instanceof Object`) @@ -1849,14 +1849,14 @@ * // => true */ var isPlainObject = !getPrototypeOf ? shimIsPlainObject : function(value) { - if (!(value && typeof value == 'object')) { + if (!(value && toString.call(value) == objectClass) || (!support.argsClass && isArguments(value))) { return false; } var valueOf = value.valueOf, objProto = typeof valueOf == 'function' && (objProto = getPrototypeOf(valueOf)) && getPrototypeOf(objProto); return objProto - ? value == objProto || (getPrototypeOf(value) == objProto && !isArguments(value)) + ? (value == objProto || getPrototypeOf(value) == objProto) : shimIsPlainObject(value); }; diff --git a/test/test.js b/test/test.js index fceede523..423da08b3 100644 --- a/test/test.js +++ b/test/test.js @@ -1406,6 +1406,13 @@ strictEqual(_.isPlainObject([1, 2, 3]), false); strictEqual(_.isPlainObject({ 'a': 1 }), true); }); + + test('should return `false` for objects without a [[Class]] of "Object"', function() { + strictEqual(_.isPlainObject(arguments), false); + strictEqual(_.isPlainObject(Error), false); + strictEqual(_.isPlainObject(Math), false); + strictEqual(_.isPlainObject(window), false); + }) }()); /*--------------------------------------------------------------------------*/