Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

深拷贝浅拷贝的区别?如何实现一个深拷贝? #134

Open
xiaotiandada opened this issue May 6, 2023 · 1 comment
Open

Comments

@xiaotiandada
Copy link
Owner

xiaotiandada commented May 6, 2023

深拷贝(Deep Copy)和浅拷贝(Shallow Copy)是在复制对象或数据结构时使用的两种不同的拷贝方式。

浅拷贝是指创建一个新的对象或数据结构,并将原始对象的引用复制给新对象。这意味着新对象与原始对象共享相同的内存地址,对其中一个对象所做的更改会影响到另一个对象。浅拷贝只复制了对象的一层,而不会递归地复制对象的内部引用。

深拷贝是指创建一个全新的对象或数据结构,并将原始对象的所有值和内部引用递归地复制到新对象中。这意味着新对象和原始对象是完全独立的,对其中一个对象所做的更改不会影响到另一个对象。

实现一个深拷贝可以使用以下几种方法:

手动递归复制:遍历对象的每个属性,并递归地复制子对象。这可以通过判断属性的类型来确定是否需要递归复制。

JSON.parse(JSON.stringify(object)):这种方法使用 JSON 序列化和反序列化来实现深拷贝。首先将对象转换为字符串,然后将其解析为新的对象。但是,该方法有一些限制,例如无法处理函数、正则表达式、循环引用等特殊情况。

使用第三方库:许多 JavaScript 第三方库(如 Lodash、jQuery)提供了深拷贝函数,可以方便地实现深拷贝操作。

需要注意的是,深拷贝可能会导致性能损耗,尤其是在处理大型或嵌套层次深的对象时。因此,在选择深拷贝方法时,需要考虑到性能和特定的需求。

综上所述,深拷贝和浅拷贝的区别在于是否递归地复制对象的内部引用。实现深拷贝可以使用递归复制、JSON 序列化等方法,或者使用第三方库提供的深拷贝函数。

const obj1 = {
  name: 'John',
  age: 30,
  dateOfBirth: new Date('1990-01-01'),
  regex: /abc/,
  array: [1, 'a', {
    a: 1,
    b: 2
  }],
  obj: {
    a: 1,
    b: 2
  }
};

function deepCopy(obj) {
  if (typeof obj !== 'object' || obj === null) {
    return obj
  }

  if (obj instanceof Date) {
    return new Date(obj)
  }

  if (obj instanceof RegExp) {
    return new RegExp(obj)
  }

  let copy

  if (Array.isArray(obj)) {
    copy = obj.map(item => deepCopy(item))
  } else {
    copy = {}
    for (let key in obj) {
      if (obj.hasOwnProperty(key)) {
        copy[key] = deepCopy(obj[key])
      }
    }
  }

  return copy
}

const obj2 = deepCopy(obj1);
console.log(obj1);
obj1.obj.a = 111
obj1.array[2].a = 111
console.log(obj2);

截屏2023-05-06 16 47 20

@xiaotiandada
Copy link
Owner Author

const getType = (target) => Object.prototype.toString.call(target).slice(8, -1)

const deepClone = (target) => {
  // 处理 原始值 null、undefined、number、string、symbol、bigInt、boolean
  if (target === null || typeof target !== 'object') {
    return target;
  }

  // 处理 array
  if (Array.isArray(target)) {
    return target.map((item) => deepClone(item));
  }

  // 处理 function
  if (getType(target) === 'Function') {
    // function 声明需要用"("、")"包裹
    return eval(`${target.toString()}`).bind(this);
  }

  // 拷贝日期
  if (getType(target) === 'Date') {
    return new Date(target.valueOf());
  }

  // 拷贝正则
  if (getType(target) === 'RegExp') {
    return new RegExp(target);
  }

  // 处理 map
  if (getType(target) === 'Map') {
    let map = new Map();
    target.forEach((v, k) => {
      map.set(k, deepClone(v));
    });
    return map;
  }

  // 处理 set
  if (getType(target) === 'Set') {
    let set = new Set();
    for (const val of target.values()) {
      set.add(deepClone(val));
    }
    return set;
  }
  // 处理 object
  if (getType(target) === 'Object') {
    let cloneTarget = {}
    for (const key in target) {
      if (target.hasOwnProperty(key)) {
        cloneTarget[key] = deepClone(target[key])
      }
    }
    return cloneTarget
  }

  return target;
}

const originalObj = {
  name: 'John',
  age: 30,
  address: {
    city: 'New York',
    zip: '10001',
  },
  fn: () => {
    console.log('fn')
  },
  time: new Date(),
  reg: new RegExp('/*/'),
  map: new Map([['John', '1'], ['J', '2']]),
  set: new Set(['a', 'b', 'c'])
};

const clonedObj = deepClone(originalObj)

originalObj.name = '111'
originalObj.address.zip = '1111111111111111111'
originalObj.set = new Set(['a', 'b', 'c', 'd', 'e', 'f'])
console.log('clonedObj', originalObj);
console.log('clonedObj', clonedObj);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant