Ensure _.assign, _.extend, _.defaults, and _.merge coerce values to objects.

This commit is contained in:
John-David Dalton
2015-07-10 00:28:49 -07:00
parent c75ac3ac64
commit 31a7ac1e81
2 changed files with 27 additions and 25 deletions

View File

@@ -2989,6 +2989,7 @@
customizer = length < 3 ? undefined : customizer; customizer = length < 3 ? undefined : customizer;
length = 1; length = 1;
} }
object = toObject(object);
while (++index < length) { while (++index < length) {
var source = sources[index]; var source = sources[index];
if (source) { if (source) {
@@ -4017,7 +4018,12 @@
* @returns {*} Returns the value to assign to the destination object. * @returns {*} Returns the value to assign to the destination object.
*/ */
function mergeDefaults(objectValue, sourceValue) { function mergeDefaults(objectValue, sourceValue) {
return objectValue === undefined ? sourceValue : merge(objectValue, sourceValue, mergeDefaults); if (objectValue === undefined) {
return sourceValue;
}
return isObject(objectValue)
? merge(objectValue, sourceValue, mergeDefaults)
: objectValue;
} }
/** /**
@@ -8575,9 +8581,6 @@
* // => { 'fruits': ['apple', 'banana'], 'vegetables': ['beet', 'carrot'] } * // => { 'fruits': ['apple', 'banana'], 'vegetables': ['beet', 'carrot'] }
*/ */
var merge = createAssigner(function baseMerge(object, source, customizer, stackA, stackB) { var merge = createAssigner(function baseMerge(object, source, customizer, stackA, stackB) {
if (!isObject(object)) {
return object;
}
var isSrcArr = isArrayLike(source) && (isArray(source) || isTypedArray(source)), var isSrcArr = isArrayLike(source) && (isArray(source) || isTypedArray(source)),
props = isSrcArr ? undefined : keysIn(source); props = isSrcArr ? undefined : keysIn(source);
@@ -8639,9 +8642,11 @@
*/ */
var assign = createAssigner(function(object, source, customizer) { var assign = createAssigner(function(object, source, customizer) {
var props = keys(source); var props = keys(source);
return customizer if (customizer) {
? copyObjectWith(source, props, customizer, object) copyObjectWith(source, props, customizer, object);
: copyObject(source, props, object) } else {
copyObject(source, props, object);
}
}); });
/** /**
@@ -8705,11 +8710,7 @@
* // => { 'user': 'barney', 'age': 36 } * // => { 'user': 'barney', 'age': 36 }
*/ */
var defaults = restParam(function(args) { var defaults = restParam(function(args) {
var object = args[0]; args.push(undefined, extendDefaults);
if (object == null) {
return object;
}
args.push(extendDefaults);
return extend.apply(undefined, args); return extend.apply(undefined, args);
}); });
@@ -8732,11 +8733,7 @@
* *
*/ */
var defaultsDeep = restParam(function(args) { var defaultsDeep = restParam(function(args) {
var object = args[0]; args.push(undefined, mergeDefaults);
if (object == null) {
return object;
}
args.push(mergeDefaults);
return merge.apply(undefined, args); return merge.apply(undefined, args);
}); });
@@ -8758,9 +8755,11 @@
*/ */
var extend = createAssigner(function(object, source, customizer) { var extend = createAssigner(function(object, source, customizer) {
var props = keysIn(source); var props = keysIn(source);
return customizer if (customizer) {
? copyObjectWith(source, props, customizer, object) copyObjectWith(source, props, customizer, object);
: copyObject(source, props, object) } else {
copyObject(source, props, object);
}
}); });
/** /**

View File

@@ -5058,12 +5058,15 @@
isAssign = methodName == 'assign', isAssign = methodName == 'assign',
isDefaults = methodName == 'defaults'; isDefaults = methodName == 'defaults';
test('`_.' + methodName + '` should pass thru falsey `object` values', 1, function() { test('`_.' + methodName + '` should coerce primitives to objects', 1, function() {
var expected = _.map(falsey, _.constant(true));
var actual = _.map(falsey, function(object, index) { var actual = _.map(falsey, function(object, index) {
return index ? func(object) : func(); var result = index ? func(object) : func();
return _.isEqual(result, Object(object));
}); });
deepEqual(actual, falsey); deepEqual(actual, expected);
}); });
test('`_.' + methodName + '` should assign own ' + (isAssign ? '' : 'and inherited ') + 'source properties', 1, function() { test('`_.' + methodName + '` should assign own ' + (isAssign ? '' : 'and inherited ') + 'source properties', 1, function() {
@@ -5122,7 +5125,7 @@
var actual = _.map([null, undefined], function(value) { var actual = _.map([null, undefined], function(value) {
try { try {
return _.isEqual(func(value, { 'a': 1 }), value); return _.isEqual(func(value, { 'a': 1 }), {});
} catch(e) { } catch(e) {
return false; return false;
} }
@@ -11667,7 +11670,7 @@
expected = { 'a': { 'b': 1, 'c': 3 } }; expected = { 'a': { 'b': 1, 'c': 3 } };
var defaultsDeep = _.partialRight(_.merge, function deep(value, other) { var defaultsDeep = _.partialRight(_.merge, function deep(value, other) {
return _.merge(value, other, deep); return _.isObject(value) ? _.merge(value, other, deep) : value;
}); });
deepEqual(defaultsDeep(object, source), expected); deepEqual(defaultsDeep(object, source), expected);