Skip to content

深度克隆

🕒 Published at:

使用MessageChannel实现深度克隆

兼容浏览器环境和Node.js环境

js
function deepClone(obj) {
  return new Promise((resolve) => {
    const { port1, port2 } = new MessageChannel()
    port1.postMessage(obj)
    port2.onmessage = (message) => {
      resolve(message.data)
      // 如果不加这两行代码,在Node环境中会一直挂起,不会结束
      port1.close()
      port2.close()
    }
  })
}

有循环引用的对象也能原封克隆

深度克隆的通用方法

支持Object、Array、Date、RegExp、DOM

js
function deepClone(sourceObj) {
    if (typeof sourceObj !== 'object')
        return;
    let newObj = sourceObj instanceof Array ? [] : {};
    for (let key in sourceObj) {
        if (sourceObj.hasOwnProperty(key)) {
            if (!(key in newObj)) {
                if (sourceObj[key] instanceof Date) {
                    newObj[key] = new Date(sourceObj[key].getTime());
                }
                else if (sourceObj[key] instanceof RegExp) {
                    newObj[key] = new RegExp(sourceObj[key]);
                }
                else if (typeof sourceObj[key] === 'object' &&
                    sourceObj[key].nodeType === 1) {
                    let domEle = document.getElementsByTagName(sourceObj[key].nodeName)[0];
                    newObj[key] = domEle.cloneNode(true);
                }
                else {
                    newObj[key] =
                        typeof sourceObj[key] === 'object'
                            ? deepClone(sourceObj[key])
                            : sourceObj[key];
                }
            }
        }
    }
    return newObj;
}

深度克隆的其他方法

lodash-es的cloneDeep、cloneDeepWith