先来实现一个最简版的 deepClone
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| function deepClone(obj) { if ( obj == null || typeof obj == "string" || typeof obj == "boolean" || typeof obj == "number" ) { return obj; } if (Array.isArray(obj)) { let temp = []; for (let i = 0; i < obj.length; i++) { temp[i] = deepClone(obj[i]); } return temp; } else if (typeof obj == "object") { let temp = {}; for (let k of Object.keys(obj)) { temp[k] = deepClone(obj[k]); } return temp; } }
|
迭代版本的 deepClone
最近 EDA 项目在解决一些性能上的问题,首当其冲的就是 deepClone,各种地方都在用,且十分卡性能。如何解决这个问题呢?
由于我们项目中的 deepClone 是一个递归版本的 deepClone,所以应该可以通过把它改成迭代版的 deepClone 来提速。
用栈来实现迭代。函数调用栈本身也是栈,但开销肯定比自己写的栈要大一些。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
| function toString(a) { return Object.prototype.toString.call(a).slice(8, -1); }
function isObj(a) { return toString(a) === "Object"; }
function isNum(a) { return toString(a) === "Number"; }
function isStr(a) { return toString(a) === "String"; }
function isBool(a) { return toString(a) === "Boolean"; }
function isSymbol(a) { return toString(a) === "Symbol"; }
function isBigInt(a) { return toString(a) === "BigInt"; }
function isFunction(a) { return toString(a) === "Function"; }
function isRegExp(a) { return toString(a) === "RegExp"; }
function isDate() { return toString(a) === "Date"; }
function isError() { return toString(a) === "Error"; }
function
function isPrim(a) { return ( isNum(a) || isStr(a) || isBool(a) || isSymbol(a) || isBigInt(a) || isFunction(a) || a === null || a === void 0 ); }
function deepCloneStack(obj) { if (isPrim(obj)) { return obj; } const root = Array.isArray(obj) ? [] : {}; const stack = [[{ root }, obj, "root"]];
while (stack.length > 0) { let [target, obj, key] = stack.pop(); if (Array.isArray(obj)) { if (!target[key]) { target[key] = new Array(obj.length); } for (let k = 0; k < obj.length; k++) { if (isPrim(obj[k])) { target[key][k] = obj[k]; } else { stack.push([target[key], obj[k], k]); } } } else { if (!target[key]) { target[key] = {}; } for (let k in obj) { if (isPrim(obj[k])) { target[key][k] = obj[k]; } else { stack.push([target[key], obj[k], k]); } } } } return root; }
|
在线运行地址
不过很遗憾的是迭代版本速度比递归还要慢,估计是因为 js 的数组性能太差导致的。