baseClone.js 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. import Stack from './Stack';
  2. import arrayEach from './arrayEach';
  3. import assignValue from './assignValue';
  4. import baseAssign from './baseAssign';
  5. import baseForOwn from './baseForOwn';
  6. import copyArray from './copyArray';
  7. import copySymbols from './copySymbols';
  8. import getTag from './getTag';
  9. import initCloneArray from './initCloneArray';
  10. import initCloneByTag from './initCloneByTag';
  11. import initCloneObject from './initCloneObject';
  12. import isArray from '../isArray';
  13. import isHostObject from './isHostObject';
  14. import isObject from '../isObject';
  15. /** `Object#toString` result references. */
  16. var argsTag = '[object Arguments]',
  17. arrayTag = '[object Array]',
  18. boolTag = '[object Boolean]',
  19. dateTag = '[object Date]',
  20. errorTag = '[object Error]',
  21. funcTag = '[object Function]',
  22. genTag = '[object GeneratorFunction]',
  23. mapTag = '[object Map]',
  24. numberTag = '[object Number]',
  25. objectTag = '[object Object]',
  26. regexpTag = '[object RegExp]',
  27. setTag = '[object Set]',
  28. stringTag = '[object String]',
  29. symbolTag = '[object Symbol]',
  30. weakMapTag = '[object WeakMap]';
  31. var arrayBufferTag = '[object ArrayBuffer]',
  32. float32Tag = '[object Float32Array]',
  33. float64Tag = '[object Float64Array]',
  34. int8Tag = '[object Int8Array]',
  35. int16Tag = '[object Int16Array]',
  36. int32Tag = '[object Int32Array]',
  37. uint8Tag = '[object Uint8Array]',
  38. uint8ClampedTag = '[object Uint8ClampedArray]',
  39. uint16Tag = '[object Uint16Array]',
  40. uint32Tag = '[object Uint32Array]';
  41. /** Used to identify `toStringTag` values supported by `_.clone`. */
  42. var cloneableTags = {};
  43. cloneableTags[argsTag] = cloneableTags[arrayTag] =
  44. cloneableTags[arrayBufferTag] = cloneableTags[boolTag] =
  45. cloneableTags[dateTag] = cloneableTags[float32Tag] =
  46. cloneableTags[float64Tag] = cloneableTags[int8Tag] =
  47. cloneableTags[int16Tag] = cloneableTags[int32Tag] =
  48. cloneableTags[mapTag] = cloneableTags[numberTag] =
  49. cloneableTags[objectTag] = cloneableTags[regexpTag] =
  50. cloneableTags[setTag] = cloneableTags[stringTag] =
  51. cloneableTags[symbolTag] = cloneableTags[uint8Tag] =
  52. cloneableTags[uint8ClampedTag] = cloneableTags[uint16Tag] =
  53. cloneableTags[uint32Tag] = true;
  54. cloneableTags[errorTag] = cloneableTags[funcTag] =
  55. cloneableTags[weakMapTag] = false;
  56. /**
  57. * The base implementation of `_.clone` and `_.cloneDeep` which tracks
  58. * traversed objects.
  59. *
  60. * @private
  61. * @param {*} value The value to clone.
  62. * @param {boolean} [isDeep] Specify a deep clone.
  63. * @param {Function} [customizer] The function to customize cloning.
  64. * @param {string} [key] The key of `value`.
  65. * @param {Object} [object] The parent object of `value`.
  66. * @param {Object} [stack] Tracks traversed objects and their clone counterparts.
  67. * @returns {*} Returns the cloned value.
  68. */
  69. function baseClone(value, isDeep, customizer, key, object, stack) {
  70. var result;
  71. if (customizer) {
  72. result = object ? customizer(value, key, object, stack) : customizer(value);
  73. }
  74. if (result !== undefined) {
  75. return result;
  76. }
  77. if (!isObject(value)) {
  78. return value;
  79. }
  80. var isArr = isArray(value);
  81. if (isArr) {
  82. result = initCloneArray(value);
  83. if (!isDeep) {
  84. return copyArray(value, result);
  85. }
  86. } else {
  87. var tag = getTag(value),
  88. isFunc = tag == funcTag || tag == genTag;
  89. if (tag == objectTag || tag == argsTag || (isFunc && !object)) {
  90. if (isHostObject(value)) {
  91. return object ? value : {};
  92. }
  93. result = initCloneObject(isFunc ? {} : value);
  94. if (!isDeep) {
  95. return copySymbols(value, baseAssign(result, value));
  96. }
  97. } else {
  98. return cloneableTags[tag]
  99. ? initCloneByTag(value, tag, isDeep)
  100. : (object ? value : {});
  101. }
  102. }
  103. // Check for circular references and return its corresponding clone.
  104. stack || (stack = new Stack);
  105. var stacked = stack.get(value);
  106. if (stacked) {
  107. return stacked;
  108. }
  109. stack.set(value, result);
  110. // Recursively populate clone (susceptible to call stack limits).
  111. (isArr ? arrayEach : baseForOwn)(value, function(subValue, key) {
  112. assignValue(result, key, baseClone(subValue, isDeep, customizer, key, value, stack));
  113. });
  114. return isArr ? result : copySymbols(value, result);
  115. }
  116. export default baseClone;