baseMergeDeep.js 2.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667
  1. var arrayCopy = require('./arrayCopy'),
  2. isArguments = require('../lang/isArguments'),
  3. isArray = require('../lang/isArray'),
  4. isArrayLike = require('./isArrayLike'),
  5. isPlainObject = require('../lang/isPlainObject'),
  6. isTypedArray = require('../lang/isTypedArray'),
  7. toPlainObject = require('../lang/toPlainObject');
  8. /**
  9. * A specialized version of `baseMerge` for arrays and objects which performs
  10. * deep merges and tracks traversed objects enabling objects with circular
  11. * references to be merged.
  12. *
  13. * @private
  14. * @param {Object} object The destination object.
  15. * @param {Object} source The source object.
  16. * @param {string} key The key of the value to merge.
  17. * @param {Function} mergeFunc The function to merge values.
  18. * @param {Function} [customizer] The function to customize merged values.
  19. * @param {Array} [stackA=[]] Tracks traversed source objects.
  20. * @param {Array} [stackB=[]] Associates values with source counterparts.
  21. * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
  22. */
  23. function baseMergeDeep(object, source, key, mergeFunc, customizer, stackA, stackB) {
  24. var length = stackA.length,
  25. srcValue = source[key];
  26. while (length--) {
  27. if (stackA[length] == srcValue) {
  28. object[key] = stackB[length];
  29. return;
  30. }
  31. }
  32. var value = object[key],
  33. result = customizer ? customizer(value, srcValue, key, object, source) : undefined,
  34. isCommon = result === undefined;
  35. if (isCommon) {
  36. result = srcValue;
  37. if (isArrayLike(srcValue) && (isArray(srcValue) || isTypedArray(srcValue))) {
  38. result = isArray(value)
  39. ? value
  40. : (isArrayLike(value) ? arrayCopy(value) : []);
  41. }
  42. else if (isPlainObject(srcValue) || isArguments(srcValue)) {
  43. result = isArguments(value)
  44. ? toPlainObject(value)
  45. : (isPlainObject(value) ? value : {});
  46. }
  47. else {
  48. isCommon = false;
  49. }
  50. }
  51. // Add the source value to the stack of traversed objects and associate
  52. // it with its merged value.
  53. stackA.push(srcValue);
  54. stackB.push(result);
  55. if (isCommon) {
  56. // Recursively merge objects and arrays (susceptible to call stack limits).
  57. object[key] = mergeFunc(result, srcValue, customizer, stackA, stackB);
  58. } else if (result === result ? (result !== value) : (value === value)) {
  59. object[key] = result;
  60. }
  61. }
  62. module.exports = baseMergeDeep;