数组深拷贝和浅拷贝

//深拷贝
var arr1 = [1, 2, 3];
var arr2 = arr1.slice();
arr1.push(4);
console.log(arr2)      //[1, 2, 3]
//浅拷贝
var arr1 = [{a:1}];
var arr2 = arr1.slice();
arr1[0].a = 2;
console.log(arr2[0].a)          //2

同样的方法,一会是深拷贝一会是浅拷贝,对数组来说,深拷贝和浅拷贝得看数组的格式吗?

阅读 4.7k
6 个回答

高级语言都是相通的,浅copy指的是arr1, arr身份不同,但是每个项目引用的对象还是同一个,所以当你push的时候,是放到了arr1的地址空间中,而修改{a:1}时,arr1和 arr2都引用了该对象,所以自然就都修改了。

看个python的例子:

a = [1, 2, 3, {'a': 1}]
b = a.copy()

b.append(4)
print(a)  # [1, 2, 3, {'a': 1}]
b[3]['a'] = 5
print(a)  # 1, 2, 3, {'a': 5}]

print(id(a), id(b)) # 2258595680904 2258597356744 a, b 不同对象
print(id(a[3]), id(b[3]))  # 1796950875736 1796950875736 a[3], b[3] 指向同一个字典对象

用JSON.parse(JSON.stringtify(arr))

这就要分 基本数据类型和引用数据类型
Number String Boolean NullUndefined属于基本数据类型,基本数据类型是按值访问的,直接等号赋值是值复制
Object Array Function Data等 属于引用数据类型,引用数据类型只能操作对象在栈内存中的引用地址,等号赋值是引用赋值
你第一个 截取的是 1 2 3这三个数字返回数组,因为数字是基本数据类型 所以直接是值复制
第第二个 截取的是 {a:1}这个对象,对象是引用数据类型,复制的是引用地址,使arr1arr2指向同一引用地址,所以更改arr1arr2也会变化

第一次之所以可以称为深拷贝,是因为里面元素都是基本类型呀,里面有引用类型的数据了就不行了,正常深拷贝你要判断每一个子元素的类型,可以用递归的方法去完成拷贝

方法1:

var cloneObj = function (obj) {
    var str, newobj = obj.constructor === Array ? [] : {};
    if (typeof obj !== 'object') {
        return;
    } else if (window.JSON) {
        str = JSON.stringify(obj), //序列化对象
            newobj = JSON.parse(str); //还原
    } else {
        for (var i in obj) {
            newobj[i] = typeof obj[i] === 'object' ? cloneObj(obj[i]) : obj[i];
        }
    }
    return newobj;
};

方法2:

function deepClone(obj){    
  if(!obj&& typeof obj!== 'object'){      
    return;    
  }    
  var newObj= obj.constructor === Array ? [] : {};    
  for(var key in obj){       
    if(obj[key]){          
      if(obj[key] && typeof obj[key] === 'object'){  
        newObj[key] = obj[key].constructor === Array ? [] : {}; 
        //递归
        newObj[key] = deepClone(obj[key]);          
      }else{            
        newObj[key] = obj[key];         
      }       
    }    
  }    
  return newObj; 
}
var arr=[{a:1,b:2},{a:3,b:4}]
var newArr=deepClone(arr)
console.log(arr[0])//{a:1,b:2}
newArr[0].a=123
console.log(arr[0])//{a:1,b:2}

还有一个方法就是简单粗暴法!原理很简单,就是先把对象转成字符串,再把字符串转成对象!

var newArr2=JSON.parse(JSON.stringify(arr));
console.log(arr[0])//{a:1,b:2}
newArr2[0].a=123
console.log(arr[0])//{a:1,b:2}

首先,都是浅拷贝。第一种数据存放基本类型,数组中存放的就是基本类型的值,拷贝的就是基本类型的值,第二种存放的是对象,存放的是对象的地址,拷贝的就是对象的地址。

看一张图吧,你应该就可以明白了。

图片描述

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题