今天见到一种很巧的deepClone的实现,之前写深拷贝代码都会写很长,而且各种判断;或者用JSON.parse(JSON.stringify(obj))
的方式,但是这种方式如果有循环引用则会报错。
这段代码通过使用Message Channel
巧妙地解决了循环引用的问题,实现了深拷贝。
1 2 3 4 5 6 7 8 9
| function deepClone(obj) { return new Promise((resolve) => { const { port1, port2 } = new MessageChannel() port1.postMessage(obj) port2.onmessage = (msg) => { resolve(msg.data) } }) }
|
不过需要注意的是,该代码仍然无法克隆function,也会丢失Symbol作为key的属性。
最后附上经典的深度克隆代码:
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
| function deepCopy(obj, cache = []) { if (obj === null || typeof obj !== 'object') { return obj } const objType = Object.prototype.toString.call(obj).slice(8, -1) if (objType === 'Symbol') { return Symbol(obj.description) } if (objType === 'RegExp') { return new RegExp(obj) } if (objType === 'Date') { return new Date(obj) } if (objType === 'Error') { return new Error(obj) } const hit = cache.filter((c) => c.original === obj)[0] if (hit) { return hit.copy } const copy = Array.isArray(obj) ? [] : {} cache.push({ original: obj, copy }) Object.keys(obj).forEach((key) => { copy[key] = this.deepCopy(obj[key], cache) }) const symbolKeys = Object.getOwnPropertySymbols(obj) for (const sKey of symbolKeys) { copy[sKey] = deepCopy(obj[sKey], cache) } return copy }
|