深拷贝函数

254 阅读1分钟

JSON.parse(JSON.stringify(obj))的弊端

  1. 这种深拷贝的方式其实对于函数,Symbol等是无法处理

  2. 并且如果存在对象的循环引用, 也会报错的

image.png

基本的深拷贝

/**
* 判断是否是一个对象
* @param {} value 
* @returns 
*/
function isObject(value) {
  const valueType = typeof value;
  return (value !== null) && 
  (valueType === 'object' || valueType === 'function') 
  // function 也是个对象
}

function deepClone(originValue) {
  // 如果不是对象是基本数据类型直接返回
  if (!isObject(originValue)) {
      return originValue
  }
  const newObject = {}
  for (const key in originValue) {
      newObject[key] = deepClone(originValue[key])
  }
  return newObject;
}

// 测试代码

let obj = {
  a: 1,
  b: 3,
  c: {
      d: {
          f: 'test'
      }
  }
}

let cloneObj = deepClone(obj);
cloneObj.a = 'hello world'
console.log(obj, 'obj')
console.log(cloneObj, 'cloneObj')

输出结果

image.png

比较全的深拷贝

/**
 * 判断是否是一个对象
 * @param {} value 
 * @returns 
 */
function isObject(value) {
    const valueType = typeof value;
    return (value !== null) && (valueType === 'object' || valueType === 'function') // function 也是个对象
}

function deepClone(originValue) {
    // 是否是一个set类型
    if (originValue instanceof Set) {
        return new Set([...originValue]);
    }
    // 判断如果是symbol, 那么创建一个新的symbol
    if (typeof originValue === 'symbol') {
        return Symbol(originValue.description);
    }
    // 判断 如果是函数类型直接返回function
    if (typeof originValue === 'function') {
        return originValue;
    }
    // 如果不是对象是基本数据类型直接返回
    if (!isObject(originValue)) {
        return originValue
    }
    // 判断传入的是数组还是对象
    const newObject = Array.isArray(originValue) ? [] : {}
    for (const key in originValue) {
        newObject[key] = deepClone(originValue[key])
    }
    // 对 symbol的key进行特殊处理
    const symbolKeys = Object.getOwnPropertySymbols(originValue)
    for (const sKey of symbolKeys) {
        newObject[sKey] = deepClone(originValue[sKey]);
    }
    return newObject;
}

// 测试代码
let s1 = Symbol('ssss');
let s2 = Symbol('ddd');

let obj = {
    name: 'coderAriel',
    age: 30,
    friend: {
        name: 'james',
        address: '广州'
    },
    hobbies: ['aaa', 'bbb', 'ccc'],
    foo: function () {
        console.log('foo function');
    },
    [s1]: 'ssss',
    s2: s2,
    set: new Set(["aaa", 'bbb', 'ccc']),
}

let cloneObj = deepClone(obj);
cloneObj.a = 'hello world'
console.log(obj, 'obj')
console.log(cloneObj, 'cloneObj')
console.log(cloneObj.s2 == obj.s2, 'symbol是否相等');

结果

image.png