手动实现浅拷贝

141 阅读2分钟

  • 场景

      let obj1 = {        name: "bello",        age: 18,        sayHello: function () {          console.log("你好呀");        },        details: {          height: "180cm",          weight: "70kg",          hobby: ["打游戏", "跑步", "看电影"],        },      };      let obj2 = obj1;      obj2.age = 20;      console.log("obj1", obj1);      console.log("obj2", obj2);

上面例子中,把 obj1 的内容赋值给 obj2,当修改obj2 中属性 age 值为20后,打印结果如下:



发现 obj1 中的 age 值也变成了 20,这是因为当我们将变量赋值给另外一个变量时,复制的是原本变量的地址(指针),即 obj1 和 obj2 同时引用了同一个内存地址,当我们进行数据修改的时候,就会修改存放在地址(指针),也就导致了两个变量的值都发生了改变。

所以为了解决上面的问题就得使用深浅拷贝

  • 浅拷贝

还是以上面场景为例:

      let obj1 = {        name: "bello",        age: 18,        sayHello: function () {          console.log("你好呀");        },        details: {          height: "180cm",          weight: "70kg",          hobby: ["打游戏", "跑步", "看电影"],        },      };      // 为了实现修改 obj2 中的属性值不会影响 obj1,      // 可以循环 obj1 将每个属性挨个添加给 obj2      let obj2 = {};      for (var key in obj1) {        obj2[key] = obj1[key];      }      obj2.age = 20;      console.log("obj1", obj1);      console.log("obj2", obj2);

运行代码,我们再来看看结果:


修改 obj2 中的属性时,obj1中属性并没有变,这样就实现了一个浅拷贝功能

  • 深拷贝

其实浅拷贝在大部分场景下都能胜任需求了,但是到遇到数据比较复杂,对象拥有多层嵌套时这样还是会出问题。

我们还是以上面为例:

      let obj1 = {        name: "bello",        age: 18,        sayHello: function () {          console.log("你好呀");        },        details: {          height: "180cm",          weight: "70kg",          hobby: ["打游戏", "跑步", "看电影"],        },      };      // 如果要修改 details 中属性时      let obj2 = {};      for (var key in obj1) {        obj2[key] = obj1[key];      }      obj2.details.weight = "80kg";      console.log("obj1", obj1);      console.log("obj2", obj2);

当修改 obj2 深层属性 weight 时,结果如下图


obj1 中的 weight 属性值同步也被改变了,不难发现这是因为 循环 obj1 时,仅仅只是将 obj1 中的第一层属性添加在 obj2 上,而更深一层的 weight 属性并没有单独拿出来给 obj2 ,所以也就导致了 obj1 和 obj2 中 weight 属性依然指向同一个地址


那么解决这个问题可以使用递归的思想,在循环的时候挨个判断每个属性,如果是引用数据类型(Object,Array)就再次循环赋值

依然以上面为例:      let obj1 = {        name: 'bello',        age: 18,        sayHello: function () {          console.log('你好呀')        },        details: {          height: '180cm',          weight: '70kg',          hobby: ['打游戏', '跑步', '看电影']        }      }      function colp(obj) {        let newObj = {}        for (let key in obj) {          if (typeof obj[key] == 'object' && obj[key] != null) {            newObj[key] = colp(obj[key])          } else {            newObj[key] = obj[key]          }        }        return newObj      }      let obj2 = colp(obj1)      obj2.details.weight = '80kg'      console.log('obj1', obj1)      console.log('obj2', obj2)

打开控制台,结果真的 Amazing 啊!obj1的weight属性值并没有改变


这样就实现了一个简单的深拷贝啦