cloneDeep.js 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. "use strict";
  2. function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
  3. var toString = Object.prototype.toString;
  4. function __type(x) {
  5. // fix typeof null = object
  6. if (x === null) {
  7. return 'null';
  8. }
  9. var t = _typeof(x);
  10. if (t !== 'object') {
  11. return t;
  12. }
  13. var cls;
  14. var clsLow;
  15. try {
  16. cls = toString.call(x).slice(8, -1);
  17. clsLow = cls.toLowerCase();
  18. } catch (e) {
  19. // ie下的 activex对象
  20. return 'object';
  21. }
  22. if (clsLow !== 'object') {
  23. return clsLow;
  24. }
  25. if (x.constructor === Object) {
  26. return clsLow;
  27. } // Object.create(null)
  28. try {
  29. /* eslint-disable no-proto */
  30. if (Object.getPrototypeOf(x) === null || x.__proto__ === null) {
  31. /* eslint-enable no-proto */
  32. return 'object';
  33. }
  34. } catch (e) {//
  35. }
  36. try {
  37. var cname = x.constructor.name;
  38. if (typeof cname === 'string') {
  39. return cname;
  40. }
  41. } catch (e) {// 无constructor
  42. } // function A() {}; A.prototype.constructor = null; new A
  43. return 'unknown';
  44. }
  45. function SimpleWeakmap() {
  46. this.cacheArray = [];
  47. }
  48. var UNIQUE_KEY = "com.yanhaijing.jsmini.clone".concat(new Date().getTime());
  49. SimpleWeakmap.prototype.set = function (key, value) {
  50. this.cacheArray.push(key);
  51. key[UNIQUE_KEY] = value;
  52. };
  53. SimpleWeakmap.prototype.get = function (key) {
  54. return key[UNIQUE_KEY];
  55. };
  56. SimpleWeakmap.prototype.clear = function () {
  57. for (var i = 0; i < this.cacheArray.length; i++) {
  58. var key = this.cacheArray[i];
  59. delete key[UNIQUE_KEY];
  60. }
  61. this.cacheArray.length = 0;
  62. };
  63. function getWeakMap() {
  64. var result;
  65. if (typeof WeakMap !== 'undefined' && __type(WeakMap) === 'function') {
  66. result = new WeakMap();
  67. if (__type(result) === 'weakmap') {
  68. return result;
  69. }
  70. }
  71. result = new SimpleWeakmap();
  72. return result;
  73. }
  74. function isClone(x) {
  75. var t = __type(x);
  76. return t === 'object' || t === 'array';
  77. }
  78. function hasOwnProp(obj, key) {
  79. return Object.prototype.hasOwnProperty.call(obj, key);
  80. }
  81. function copy(x) {
  82. var uniqueData = getWeakMap();
  83. var t = __type(x);
  84. var root = x;
  85. if (t === 'array') {
  86. root = [];
  87. } else if (t === 'object') {
  88. root = {};
  89. } // 循环数组
  90. var loopList = [{
  91. parent: root,
  92. key: undefined,
  93. data: x
  94. }];
  95. while (loopList.length) {
  96. // 深度优先
  97. var node = loopList.pop();
  98. var parent = node.parent;
  99. var key = node.key;
  100. var source = node.data;
  101. var tt = __type(source); // 初始化赋值目标,key为undefined则拷贝到父元素,否则拷贝到子元素
  102. var target = parent;
  103. if (typeof key !== 'undefined') {
  104. parent[key] = tt === 'array' ? [] : {};
  105. target = parent[key];
  106. } // 复杂数据需要缓存操作
  107. if (isClone(source)) {
  108. // 命中缓存,直接返回缓存数据
  109. var uniqueTarget = uniqueData.get(source);
  110. if (uniqueTarget) {
  111. parent[key] = uniqueTarget;
  112. continue; // 中断本次循环
  113. } // 未命中缓存,保存到缓存
  114. uniqueData.set(source, target);
  115. }
  116. if (tt === 'array') {
  117. for (var i = 0; i < source.length; i++) {
  118. if (isClone(source[i])) {
  119. // 下一次循环
  120. loopList.push({
  121. parent: target,
  122. key: i,
  123. data: source[i]
  124. });
  125. } else {
  126. target[i] = source[i];
  127. }
  128. }
  129. } else if (tt === 'object') {
  130. for (var k in source) {
  131. if (hasOwnProp(source, k)) {
  132. if (k === UNIQUE_KEY) {
  133. continue;
  134. }
  135. if (isClone(source[k])) {
  136. // 下一次循环
  137. loopList.push({
  138. parent: target,
  139. key: k,
  140. data: source[k]
  141. });
  142. } else {
  143. target[k] = source[k];
  144. }
  145. }
  146. }
  147. }
  148. }
  149. uniqueData.clear && uniqueData.clear();
  150. return root;
  151. }
  152. module.exports = {
  153. copy: copy
  154. };