js 数组深度拷贝详解

js 数组深度拷贝详解

1.我们已经知道的深拷贝和浅拷贝的区别,在于,深拷贝是拷贝值的同时拥有一个新的存储地址,而浅拷贝只是拷贝了值,而存储地址不变;这样会导致的问题是修改拷贝的值,会同时修改原数组;

但是你所知道深拷贝真的就是深拷贝吗?

浅拷贝示例:

    var arr = [1,2,3,4]
      let newArr = arr  //浅拷贝
        newArr.splice(0,1)
        console.log(arr,'原数组');  //[2, 3, 4] "原数组"
        console.log(newArr,'浅拷贝数组') //[2, 3, 4] "拷贝数组"

深拷贝示例:

第一种 利用数组api slice 和 map 返回一新数组的特性

var arr = [1,2,3,4]
      let newArr = arr.slice(0)  //深拷贝
        newArr.splice(0,1)
        console.log(arr,'原数组');  //[1, 2, 3, 4] "原数组"
        console.log(newArr,'深拷贝数组') //[2, 3, 4] "拷贝数组"

//map
 let newArr2 = arr.map(item=>{
          return item
        })
        newArr2.splice(0,1)
        console.log(arr,'原数组');  //[1, 2, 3, 4] "原数组"
        console.log(newArr2,'深拷贝数组') //[2, 3, 4] "拷贝数组"

第二种 创建新数组存储

var arr = [1,2,3,4]
let newArr3 = []
          for(var i=0 ;i<arr.length;i++){
            newArr3.push(arr[i])
          }
        newArr3.splice(0,1)
        console.log(arr,'原数组');  //[1, 2, 3, 4] "原数组"
        console.log(newArr3,'拷贝数组') //[ 2, 3, 4] "拷贝数组"

第三种 利用 JSON.stringify() ,JSON.parse() 之间的转换

var arr = [1,2,3,4]
let newArr4 =  JSON.parse(JSON.stringify(arr))
         newArr4.splice(0,1)
        console.log(arr,'原数组');  //[1, 2, 3, 4] "原数组"
        console.log(newArr4,'拷贝数组') //[ 2, 3, 4] "拷贝数组"

但是这种方法有一定缺陷,不能转换function,还有undefined

   		var arr2 =  [1,2,3,function(){console.log(11)},undefined,null]
      let newArr4 =  JSON.parse(JSON.stringify(arr2))
         newArr4.splice(0,1)
        console.log(arr2,'原数组');  //[1, 2, 3, ƒ] "原数组"
        console.log(newArr4,'拷贝数组') // [2, 3, null,null,null] "拷贝数组"
上述方法是能实现深拷贝,但我们需要了解当数组中有层级,是否能深拷贝呢?

要知道,比方一个数组 arr =[{a:1,b:2}],这个数组arr存储在一个地址中,而其中的arr[0].a存储的地址却是里另一个地址,相当于引用传递,这时简单的深拷贝将不能拷贝这个深层级的拷贝

多层级拷贝错误示例:

 var arr1 = [{a:1,b:1}]
      let newArr1 = arr1.slice(0)
          newArr1.forEach(item=>{
            delete item.a
          })
        console.log(arr1,'原数组');  //[{b:1}] "原数组"
        console.log(newArr1,'拷贝数组') //[{b:1}] "拷贝数组"


//第二种
  var arr2 = [[1,2,3],[2,3,4]]
      let newArr2 = []
      for(var i=0 ;i<arr2.length;i++){
            newArr2.push(arr2[i])
          }
        newArr2.forEach(item=>{
            item.splice(0,1)
          })
          console.log(arr2,'原数组');  //[[2,3],[3,4]] "原数组"
         console.log(newArr2,'拷贝数组') //[[2,3],[3,4]] "拷贝数组"

以上是无法实现多层级拷贝,但是JSON.stringify() ,JSON.parse() 却可以

 var arr1 = [{a:1,b:1}]
let newArr4 =  JSON.parse(JSON.stringify(arr1))
         newArr4.forEach(item=>{
            delete item.a
          })
          console.log(arr1,'原数组');  //[{a:1,b:1}] "原数组"
         console.log(newArr4,'拷贝数组') //[{b:1}] "拷贝数组"

换一个思路,既然每一层的地址不同,我们何不遍历每一层的拷贝呢

 var arr1 = [{a:1,b:1}]
 function clone(obj){
      if (obj instanceof Array) {
        var copy = [];
        for (var i = 0, len = obj.length; i < len; ++i) {
            copy[i] = clone(obj[i]);
        }
        return copy;
    }
 }
let newArr5 = clone(arr1) 
newArr5.forEach(item=>{
            delete item.a
          })
          console.log(arr1,'原数组');  //[{a:1,b:1}] "原数组"
         console.log(newArr5,'拷贝数组') //[{b:1}] "拷贝数组"

当然不同的对象有不同的clone,以下是笔者封装的方法适用于多种对象

function clone(obj) { 
    // 判断是否为空未定义
    if (null == obj || "object" != typeof obj) return obj;

    //  Date
    if (obj instanceof Date) {
        var copy = new Date();
        copy.setTime(obj.getTime());
        return copy;
    }

    //  Array
    if (obj instanceof Array) {
        var copy = [];
        for (var i = 0, len = obj.length; i < len; ++i) {
            copy[i] = clone(obj[i]);
        }
        return copy;
    }

    // Object
    if (obj instanceof Object) {
        var copy = {};
        for (var attr in obj) {
            if (obj.hasOwnProperty(attr)) copy[attr] = clone(obj[attr]);
        }
        return copy;
    }

    throw new Error("无法复制对象!不支持其类型。");
}
  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值