_baseClone.js 4.7 KB

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