直接上代码吧,然后将一些理解的东西写在代码上面
1 // 检验是否是对象的函数 2 function isObject(x) { 3 return Object.prototype.toString.call(x) === '[object Object]' 4 } 5 6 // 在数组列表中,查找是否是相同地址的对象, 7 // 有,返回该对象,否则返回null 8 function find(arr, item) { 9 for(let i = 0; i < arr.length; i++) { 10 if (arr[i].source === item) { 11 return arr[i]; 12 } 13 } 14 15 return null; 16 } 17 18 // 这是个简单的克隆, 19 // 有很多的问题, 20 // 没对参数进行校验 21 // 没对爆栈做处理 22 // 容易陷入死循环 23 function clone(x) { 24 let data = {} 25 let res = data; 26 27 for(var k in x) { 28 if (x.hasOwnProperty(k)) { 29 res[k] = clone(x[k]) 30 } else { 31 res[k] = x[k] 32 } 33 } 34 35 return res 36 } 37 38 // JSON.parse和JSON.stringify的封装 39 // 里面有递归 40 // 并且有循环检测(防死循环) 41 function cloneJson(x) { 42 return JSON.parse(JSON.stringify(x)) 43 } 44 45 // 这里做了防爆栈处理 46 // 只对对象做了克隆 47 // 但是还有防死循环没做 48 function cloneLoop(x) { 49 if(!isObject(x)) return x; 50 const root = {} 51 52 const loopList = [ 53 { 54 parent: root, 55 key: undefined, 56 data: x 57 } 58 ] 59 60 while(loopList.length) { 61 const node = loopList.pop(); 62 const parent = node.parent; 63 const key = node.key; 64 const data = node.data; 65 66 let temp = parent; 67 // 如果key为undedined 68 if (typeof key !== undefined) { 69 temp = parent[key] = {} 70 } 71 72 for (var k in data) { 73 if (data.hasOwnProperty(k)) { 74 if (isObject(data[k])) { 75 loopList.push({ 76 parent: temp, 77 key: k, 78 data: data[k] 79 }) 80 } 81 } else { 82 temp[k] = data[k] 83 } 84 } 85 } 86 87 return root 88 } 89 90 // 进一步优化 91 // 前一种方法,对象里有相同的引用,会切断引用关系 92 // 这里不会,并且能有防死循环的作用 93 function cloneForce(x) { 94 // 1.防止爆栈 95 // 2.解决引用丢失 96 if(!isObject(x)) return x; 97 98 // ============= 99 const uniqueList = []; // 用来去重 100 // ============= 101 const root = {}; 102 const loopList = [{ 103 parent: root, 104 key: undefined, 105 data: x, 106 }] 107 108 while (loopList.length) { 109 const node = loopList.pop(); 110 const parent = node.parent; 111 const key = node.key; 112 const data = node.data; 113 114 let res = parent; 115 116 if (typeof key !== 'undefined') { 117 res = parent[key] = {} 118 } 119 120 let uniqueData = find(uniqueList, data) 121 if (uniqueData) { 122 parent[key] = uniqueData.target; 123 break; 124 } 125 126 uniqueList.push({ 127 source: data, 128 target: res 129 }) 130 131 for (var k in data) { 132 if (data.hasOwnProperty(k)) { 133 if (isObject(data[k])) { 134 loopList.push({ 135 parent: res, 136 key: k, 137 data: data[k] 138 }) 139 } else { 140 res[k] = data[k] 141 } 142 } 143 } 144 145 return root; 146 } 147 } 148 149 // 用来快速创建对象 150 function createData(deep, breadth) { 151 // deep 深度 152 // breadth 广度 153 let data = {} 154 let temp = data; 155 156 for(var i = 0; i < deep; i++){ 157 temp = temp['data'] = {} 158 for (var j = 0; j < breadth; j++) { 159 temp[j] = j 160 } 161 } 162 163 return data 164 } 165 166 // 用来测试性能 167 function test(fn, time) { 168 let count = 0; 169 let startTime = new Date().getTime(); 170 while(new Date().getTime - startTime < time) { 171 fn(); 172 count++; 173 } 174 return count; 175 } 176 177 test(function () { 178 cloneForce(createData(10000)) 179 }, 2000)
参考文献:
1. https://segmentfault.com/a/1190000016672263
2.https://juejin.im/post/5e34d19de51d4558864b1d1f#heading-36