mirror of
https://github.com/whoisclebs/lodash.git
synced 2026-02-07 01:57:50 +00:00
Make _.clone and _.cloneDeep return an empty object for unsupported types.
This commit is contained in:
29
lodash.js
29
lodash.js
@@ -1500,7 +1500,10 @@
|
|||||||
result = initArrayClone(value, isDeep);
|
result = initArrayClone(value, isDeep);
|
||||||
} else if (isObject(value)) {
|
} else if (isObject(value)) {
|
||||||
result = initObjectClone(value, isDeep);
|
result = initObjectClone(value, isDeep);
|
||||||
value = (isDeep && toString.call(result) == objectClass) ? value : result;
|
if (result === null) {
|
||||||
|
isDeep = false;
|
||||||
|
result = {};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!isDeep || result === value) {
|
if (!isDeep || result === value) {
|
||||||
return result;
|
return result;
|
||||||
@@ -1521,11 +1524,15 @@
|
|||||||
stackB.push(result);
|
stackB.push(result);
|
||||||
|
|
||||||
// recursively populate clone (susceptible to call stack limits)
|
// recursively populate clone (susceptible to call stack limits)
|
||||||
(isArr ? arrayEach : baseForOwn)(value, function(valValue, key) {
|
(isArr ? arrayEach : baseForOwn)(value, function(val, key) {
|
||||||
var valClone = customizer ? customizer(valValue, key) : undefined;
|
var computed = customizer ? customizer(val, key) : undefined,
|
||||||
result[key] = typeof valClone == 'undefined'
|
useComputed = typeof computed != 'undefined',
|
||||||
? baseClone(valValue, isDeep, null, stackA, stackB)
|
isReflexive = useComputed && computed === computed;
|
||||||
: valClone;
|
|
||||||
|
if (useComputed && (isReflexive ? val === computed : val !== val)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
result[key] = useComputed ? computed : baseClone(val, isDeep, null, stackA, stackB);
|
||||||
});
|
});
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -2927,9 +2934,9 @@
|
|||||||
* Initializes an array clone.
|
* Initializes an array clone.
|
||||||
*
|
*
|
||||||
* @private
|
* @private
|
||||||
* @param {*} value The value to clone.
|
* @param {Array} array The array to clone.
|
||||||
* @param {boolean} [isDeep=false] Specify a deep clone.
|
* @param {boolean} [isDeep=false] Specify a deep clone.
|
||||||
* @returns {*} Returns the initialized clone value.
|
* @returns {Array} Returns the initialized array clone.
|
||||||
*/
|
*/
|
||||||
function initArrayClone(array, isDeep) {
|
function initArrayClone(array, isDeep) {
|
||||||
var index = -1,
|
var index = -1,
|
||||||
@@ -2953,14 +2960,14 @@
|
|||||||
* Initializes an object clone.
|
* Initializes an object clone.
|
||||||
*
|
*
|
||||||
* @private
|
* @private
|
||||||
* @param {*} value The value to clone.
|
* @param {Object} object The object to clone.
|
||||||
* @param {boolean} [isDeep=false] Specify a deep clone.
|
* @param {boolean} [isDeep=false] Specify a deep clone.
|
||||||
* @returns {*} Returns the initialized clone value.
|
* @returns {null|Object} Returns the initialized object clone.
|
||||||
*/
|
*/
|
||||||
function initObjectClone(object, isDeep) {
|
function initObjectClone(object, isDeep) {
|
||||||
var className = toString.call(object);
|
var className = toString.call(object);
|
||||||
if (!cloneableClasses[className] || isHostObject(object)) {
|
if (!cloneableClasses[className] || isHostObject(object)) {
|
||||||
return object;
|
return null;
|
||||||
}
|
}
|
||||||
var Ctor = object.constructor,
|
var Ctor = object.constructor,
|
||||||
isArgs = className == argsClass || (!lodash.support.argsClass && isArguments(object)),
|
isArgs = className == argsClass || (!lodash.support.argsClass && isArguments(object)),
|
||||||
|
|||||||
38
test/test.js
38
test/test.js
@@ -1577,11 +1577,6 @@
|
|||||||
function Klass() { this.a = 1; }
|
function Klass() { this.a = 1; }
|
||||||
Klass.prototype = { 'b': 1 };
|
Klass.prototype = { 'b': 1 };
|
||||||
|
|
||||||
var nonCloneable = {
|
|
||||||
'DOM elements': body,
|
|
||||||
'functions': Klass
|
|
||||||
};
|
|
||||||
|
|
||||||
var objects = {
|
var objects = {
|
||||||
'`arguments` objects': arguments,
|
'`arguments` objects': arguments,
|
||||||
'arrays': ['a', ''],
|
'arrays': ['a', ''],
|
||||||
@@ -1603,6 +1598,15 @@
|
|||||||
|
|
||||||
objects['arrays'].length = 3;
|
objects['arrays'].length = 3;
|
||||||
|
|
||||||
|
var nonCloneable = {
|
||||||
|
'DOM elements': body,
|
||||||
|
'functions': Klass
|
||||||
|
};
|
||||||
|
|
||||||
|
_.each(errors, function(error) {
|
||||||
|
nonCloneable[error.name + 's'] = error;
|
||||||
|
});
|
||||||
|
|
||||||
test('`_.clone` should perform a shallow clone', 2, function() {
|
test('`_.clone` should perform a shallow clone', 2, function() {
|
||||||
var expected = [{ 'a': 0 }, { 'b': 1 }],
|
var expected = [{ 'a': 0 }, { 'b': 1 }],
|
||||||
actual = _.clone(expected);
|
actual = _.clone(expected);
|
||||||
@@ -1652,13 +1656,7 @@
|
|||||||
|
|
||||||
_.forOwn(nonCloneable, function(object, key) {
|
_.forOwn(nonCloneable, function(object, key) {
|
||||||
test('`_.' + methodName + '` should not clone ' + key, 1, function() {
|
test('`_.' + methodName + '` should not clone ' + key, 1, function() {
|
||||||
strictEqual(func(object), object);
|
deepEqual(func(object), {});
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
_.each(errors, function(error) {
|
|
||||||
test('`_.' + methodName + '` should not clone ' + error.name + ' objects', 1, function() {
|
|
||||||
strictEqual(func(error), error);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1747,9 +1745,9 @@
|
|||||||
if (document) {
|
if (document) {
|
||||||
var element = document.createElement('div');
|
var element = document.createElement('div');
|
||||||
try {
|
try {
|
||||||
strictEqual(func(element), element);
|
deepEqual(func(element), {});
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
ok(false);
|
ok(false, e.message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -1855,7 +1853,7 @@
|
|||||||
try {
|
try {
|
||||||
strictEqual(combined(), undefined);
|
strictEqual(combined(), undefined);
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
ok(false);
|
ok(false, e.message);
|
||||||
}
|
}
|
||||||
notStrictEqual(combined, _.noop);
|
notStrictEqual(combined, _.noop);
|
||||||
});
|
});
|
||||||
@@ -2197,7 +2195,7 @@
|
|||||||
var callback = _.callback(value, {});
|
var callback = _.callback(value, {});
|
||||||
strictEqual(callback(object), object);
|
strictEqual(callback(object), object);
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
ok(false);
|
ok(false, e.message);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -4031,7 +4029,7 @@
|
|||||||
}
|
}
|
||||||
deepEqual(actual, expected);
|
deepEqual(actual, expected);
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
ok(false);
|
ok(false, e.message);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -4516,7 +4514,7 @@
|
|||||||
try {
|
try {
|
||||||
deepEqual(func({ 'a': 1 }, undefined, { 'b': 2 }, null), { 'a': 1, 'b': 2 });
|
deepEqual(func({ 'a': 1 }, undefined, { 'b': 2 }, null), { 'a': 1, 'b': 2 });
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
ok(false);
|
ok(false, e.message);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -6056,7 +6054,7 @@
|
|||||||
try {
|
try {
|
||||||
strictEqual(_.isEqual(element1, element2), false);
|
strictEqual(_.isEqual(element1, element2), false);
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
ok(false);
|
ok(false, e.message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -10664,7 +10662,7 @@
|
|||||||
var data = { 'a': [1, 2, 3] };
|
var data = { 'a': [1, 2, 3] };
|
||||||
strictEqual(compiled(data), '123');
|
strictEqual(compiled(data), '123');
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
ok(false);
|
ok(false, e.message);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user