JS实现多层深拷贝的简单方法

0 阅读2分钟

1.使用Json转换的方式

<script>
let a = [1,2,3,[4,5]]
let b = Json.parse(Json.stringify(a))
</script>

缺点:如果嵌套的是函数类型就不能用

2.如果嵌套的有函数类型

<script>
let obj = {
name:"Tom",
age:18,
fn(){
console.log("age:",this.age)
},
tt:{project:"kkk"},
aa:[1,2,3]
}

let obj2 = {...obj} // 浅拷贝:只复制第一层属性值(如字符串、数字等),对于嵌套的对象或数组,复制的是引用地址
obj.fn = function(){
console.log("++age:",++this.age)}

obj.fn()
obj2.fn()

obj.tt.project = "yyy"
console.log("obj",obj.tt.project)
console.log("obj2",obj2.tt.project)

obj.aa[0] = 5
console.log("obj",obj.aa)
console.log("obj2",obj2.aa)

</script>

image.png

image.png

注意到当修改函数的值时,数据不会产生相互干扰,但是当修改数组或者对象的值会有干扰,因为数组或者对象复制过去的一层都是地址,函数是因为我们修改的方式相当于重写一个函数,因此你新的函数会在内存中开辟一个新的存储空间。

3.使用递归实现深拷贝

<script>
let a = [1,2,3]
console.log(typeof a) //object

let b=null
console.log(typeof b)//object
let c=undefined
console.log(typeof c)//undefined

/**
 * 深拷贝函数:递归实现
 * @param {any} oldData 需要拷贝的数据,可以是对象、数组或基本类型
 * @return {any} 返回拷贝后的新数据,与原数据无引用关系
 */
function deepClone(oldData) {
  // 判断当前处理的数据是否为对象类型,并且不是 null(因为 typeof null === 'object')
  if (typeof oldData === 'object' && oldData != null) {
    // 根据原始数据是数组还是对象创建一个新的空数组或空对象作为结果容器
    let res = Array.isArray(oldData) ? [] : {};

    // 遍历原始对象的所有自有属性(不包括继承来的属性)
    for (let k in oldData) {
      if (oldData.hasOwnProperty(k)) {
        // 对当前属性值递归调用 deepClone 函数进行深拷贝
        // 并将返回的结果赋值给结果对象/数组对应的键
        res[k] = deepClone(oldData[k]);
      }
    }

    // 返回已经完成深拷贝的对象/数组
    return res;
  } else {
    // 如果当前数据是基本类型(如 number, string, boolean)或者函数等,则直接返回原值
    // 因为基本类型在赋值时是值传递,不会产生引用问题
    return oldData;
  }
}

</script>