mirror of
https://github.com/whoisclebs/lodash.git
synced 2026-02-08 10:17:48 +00:00
Ensure optimized isPlainObject works with objects from other documents.
Former-commit-id: 2f782b3dfc19e7ea3274132c31cd408ee2387021
This commit is contained in:
13
build.js
13
build.js
@@ -572,17 +572,6 @@
|
|||||||
return source.replace(/(?:\s*\/\/.*)*\n( +)if *\(isFunction\(\/x\/[\s\S]+?};\n\1}/, '');
|
return source.replace(/(?:\s*\/\/.*)*\n( +)if *\(isFunction\(\/x\/[\s\S]+?};\n\1}/, '');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes the `isPlainObject` fallback from `source`.
|
|
||||||
*
|
|
||||||
* @private
|
|
||||||
* @param {String} source The source to process.
|
|
||||||
* @returns {String} Returns the source with the `isPlainObject` fallback removed.
|
|
||||||
*/
|
|
||||||
function removeIsPlainObjectFallback(source) {
|
|
||||||
return source.replace(/(?:\s*\/\/.*)*\n( +)if *\(!isPlainObject[\s\S]+?};\n\1}/, '');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes the `Object.keys` object iteration optimization from `source`.
|
* Removes the `Object.keys` object iteration optimization from `source`.
|
||||||
*
|
*
|
||||||
@@ -1003,7 +992,6 @@
|
|||||||
|
|
||||||
if (!isUnderscore) {
|
if (!isUnderscore) {
|
||||||
source = removeIsArgumentsFallback(source);
|
source = removeIsArgumentsFallback(source);
|
||||||
source = removeIsPlainObjectFallback(source);
|
|
||||||
source = removeNoArgsClass(source);
|
source = removeNoArgsClass(source);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1131,7 +1119,6 @@
|
|||||||
source = removeVar(source, 'reNative');
|
source = removeVar(source, 'reNative');
|
||||||
}
|
}
|
||||||
if (isRemoved(source, 'createIterator', 'clone', 'merge')) {
|
if (isRemoved(source, 'createIterator', 'clone', 'merge')) {
|
||||||
source = removeIsPlainObjectFallback(source);
|
|
||||||
source = source.replace(/(?:\n +\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/)?\n *var iteratesOwnLast;|.+?iteratesOwnLast *=.+/g, '');
|
source = source.replace(/(?:\n +\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/)?\n *var iteratesOwnLast;|.+?iteratesOwnLast *=.+/g, '');
|
||||||
}
|
}
|
||||||
if (isRemoved(source, 'createIterator', 'isEqual')) {
|
if (isRemoved(source, 'createIterator', 'isEqual')) {
|
||||||
|
|||||||
94
lodash.js
94
lodash.js
@@ -965,6 +965,49 @@
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A fallback implementation of `isPlainObject`.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Mixed} value The value to check.
|
||||||
|
* @param {Boolean} [skipArgsCheck=false] Internally used to skip checks for
|
||||||
|
* `arguments` objects.
|
||||||
|
* @returns {Boolean} Returns `true` if the `value` is a plain `Object` object,
|
||||||
|
* else `false`.
|
||||||
|
*/
|
||||||
|
function isPlainFallback(value, skipArgsCheck) {
|
||||||
|
// avoid non-objects and false positives for `arguments` objects
|
||||||
|
var result = false;
|
||||||
|
if (!(value && typeof value == 'object') || (!skipArgsCheck && isArguments(value))) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
// IE < 9 presents DOM nodes as `Object` objects except they have `toString`
|
||||||
|
// methods that are `typeof` "string" and still can coerce nodes to strings.
|
||||||
|
// Also check that the constructor is `Object` (i.e. `Object instanceof Object`)
|
||||||
|
var ctor = value.constructor;
|
||||||
|
if ((!noNodeClass || !(typeof value.toString != 'function' && typeof (value + '') == 'string')) &&
|
||||||
|
(!isFunction(ctor) || ctor instanceof ctor)) {
|
||||||
|
// 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 (iteratesOwnLast) {
|
||||||
|
forIn(value, function(objValue, objKey) {
|
||||||
|
result = !hasOwnProperty.call(value, objKey);
|
||||||
|
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(objValue, objKey) {
|
||||||
|
result = objKey;
|
||||||
|
});
|
||||||
|
return result === false || hasOwnProperty.call(value, result);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if a given `value` is an object created by the `Object` constructor
|
* Checks if a given `value` is an object created by the `Object` constructor
|
||||||
* assuming objects created by the `Object` constructor have no inherited
|
* assuming objects created by the `Object` constructor have no inherited
|
||||||
@@ -977,46 +1020,17 @@
|
|||||||
* @returns {Boolean} Returns `true` if the `value` is a plain `Object` object,
|
* @returns {Boolean} Returns `true` if the `value` is a plain `Object` object,
|
||||||
* else `false`.
|
* else `false`.
|
||||||
*/
|
*/
|
||||||
function isPlainObject(value, skipArgsCheck) {
|
var isPlainObject = objectTypes.__proto__ != ObjectProto ? isPlainFallback : function(value, skipArgsCheck) {
|
||||||
return value
|
if (!value) {
|
||||||
? value == ObjectProto || (value.__proto__ == ObjectProto && (skipArgsCheck || !isArguments(value)))
|
return false;
|
||||||
: false;
|
}
|
||||||
}
|
var valueOf = value.valueOf,
|
||||||
// fallback for IE
|
objProto = typeof valueOf == 'function' && valueOf.__proto__.__proto__;
|
||||||
if (!isPlainObject(objectTypes)) {
|
|
||||||
isPlainObject = function(value, skipArgsCheck) {
|
return objProto
|
||||||
// avoid non-objects and false positives for `arguments` objects
|
? value == objProto || (value.__proto__ == objProto && (skipArgsCheck || !isArguments(value)))
|
||||||
var result = false;
|
: isPlainFallback(value);
|
||||||
if (!(value && typeof value == 'object') || (!skipArgsCheck && isArguments(value))) {
|
};
|
||||||
return result;
|
|
||||||
}
|
|
||||||
// IE < 9 presents DOM nodes as `Object` objects except they have `toString`
|
|
||||||
// methods that are `typeof` "string" and still can coerce nodes to strings.
|
|
||||||
// Also check that the constructor is `Object` (i.e. `Object instanceof Object`)
|
|
||||||
var ctor = value.constructor;
|
|
||||||
if ((!noNodeClass || !(typeof value.toString != 'function' && typeof (value + '') == 'string')) &&
|
|
||||||
(!isFunction(ctor) || ctor instanceof ctor)) {
|
|
||||||
// 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 (iteratesOwnLast) {
|
|
||||||
forIn(value, function(objValue, objKey) {
|
|
||||||
result = !hasOwnProperty.call(value, objKey);
|
|
||||||
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(objValue, objKey) {
|
|
||||||
result = objKey;
|
|
||||||
});
|
|
||||||
return result === false || hasOwnProperty.call(value, result);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A shim implementation of `Object.keys` that produces an array of the given
|
* A shim implementation of `Object.keys` that produces an array of the given
|
||||||
|
|||||||
@@ -33,7 +33,7 @@
|
|||||||
delete Object._keys;
|
delete Object._keys;
|
||||||
|
|
||||||
// set to test `_.noConflict`
|
// set to test `_.noConflict`
|
||||||
_ = 1;
|
_ = {};
|
||||||
|
|
||||||
// load Lo-Dash again to overwrite the existing `_` value
|
// load Lo-Dash again to overwrite the existing `_` value
|
||||||
document.write('<script src="../' + QUnit.config.lodashFilename + '.js"><\/script>');
|
document.write('<script src="../' + QUnit.config.lodashFilename + '.js"><\/script>');
|
||||||
|
|||||||
37
test/test.js
37
test/test.js
@@ -83,6 +83,23 @@
|
|||||||
|
|
||||||
/*--------------------------------------------------------------------------*/
|
/*--------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
// add object from iframe
|
||||||
|
(function() {
|
||||||
|
if (!window.document) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var body = document.body,
|
||||||
|
iframe = document.createElement('iframe');
|
||||||
|
|
||||||
|
iframe.frameBorder = iframe.height = iframe.width = 0;
|
||||||
|
body.appendChild(iframe);
|
||||||
|
var idoc = (idoc = iframe.contentDocument || iframe.contentWindow).document || idoc;
|
||||||
|
idoc.write("<script>parent._._object = { 'a': 1, 'b': 2, 'c': 3 };<\/script>");
|
||||||
|
idoc.close();
|
||||||
|
}());
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------------------*/
|
||||||
|
|
||||||
// explicitly call `QUnit.module()` instead of `module()`
|
// explicitly call `QUnit.module()` instead of `module()`
|
||||||
// in case we are in a CLI environment
|
// in case we are in a CLI environment
|
||||||
QUnit.module('lodash');
|
QUnit.module('lodash');
|
||||||
@@ -191,6 +208,7 @@
|
|||||||
'boolean object': Object(false),
|
'boolean object': Object(false),
|
||||||
'an object': { 'a': 0, 'b': 1, 'c': 3 },
|
'an object': { 'a': 0, 'b': 1, 'c': 3 },
|
||||||
'an object with object values': { 'a': /a/, 'b': ['B'], 'c': { 'C': 1 } },
|
'an object with object values': { 'a': /a/, 'b': ['B'], 'c': { 'C': 1 } },
|
||||||
|
'an object from another document': _._object || {},
|
||||||
'null': null,
|
'null': null,
|
||||||
'a number': 3,
|
'a number': 3,
|
||||||
'a number object': Object(3),
|
'a number object': Object(3),
|
||||||
@@ -205,12 +223,8 @@
|
|||||||
_.forOwn(objects, function(object, key) {
|
_.forOwn(objects, function(object, key) {
|
||||||
test('should deep clone ' + key + ' correctly', function() {
|
test('should deep clone ' + key + ' correctly', function() {
|
||||||
var clone = _.clone(object, true);
|
var clone = _.clone(object, true);
|
||||||
|
ok(_.isEqual(object, clone));
|
||||||
|
|
||||||
if (object == null) {
|
|
||||||
equal(clone, object);
|
|
||||||
} else {
|
|
||||||
deepEqual(clone.valueOf(), object.valueOf());
|
|
||||||
}
|
|
||||||
if (_.isObject(object)) {
|
if (_.isObject(object)) {
|
||||||
ok(clone !== object);
|
ok(clone !== object);
|
||||||
} else {
|
} else {
|
||||||
@@ -747,21 +761,10 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should return `true` for like-objects from different documents', function() {
|
test('should return `true` for like-objects from different documents', function() {
|
||||||
if (window.document) {
|
|
||||||
var body = document.body,
|
|
||||||
iframe = document.createElement('iframe'),
|
|
||||||
object = { 'a': 1, 'b': 2, 'c': 3 };
|
|
||||||
|
|
||||||
body.appendChild(iframe);
|
|
||||||
var idoc = (idoc = iframe.contentDocument || iframe.contentWindow).document || idoc;
|
|
||||||
idoc.write("<script>parent._._object = { 'a': 1, 'b': 2, 'c': 3 };<\/script>");
|
|
||||||
idoc.close();
|
|
||||||
}
|
|
||||||
// ensure `_._object` is assigned (unassigned in Opera 10.00)
|
// ensure `_._object` is assigned (unassigned in Opera 10.00)
|
||||||
if (_._object) {
|
if (_._object) {
|
||||||
|
var object = { 'a': 1, 'b': 2, 'c': 3 };
|
||||||
equal(_.isEqual(object, _._object), true);
|
equal(_.isEqual(object, _._object), true);
|
||||||
body.removeChild(iframe);
|
|
||||||
delete _._object;
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
skipTest();
|
skipTest();
|
||||||
|
|||||||
Reference in New Issue
Block a user