浅拷贝,又叫浅复制,使用方法就是最简单的赋值:
var a = 1; var b = a; var c = {x: 1}; var d = c;
实际上参数传递也是用的浅拷贝
但是,在对象进行浅拷贝的时候,拷贝的内容进行修改会影响原来的变量
var a = {x:1}; var b = a; console.log(b); //{x:1} b.x = 2; console.log(b); //{x:2} console.log(a); //{x:2}
原因:对象类型的直接赋值,实际上是赋值的一个引用,或者说只是赋值了一个地址,对象的数据实际上并没有直接放在这个变量所代表的内存空间,该内存空间只是存放了一个地址,这个地址里面索引到的部分才是真正的数据,当对对象进行直接赋值,实际上是把变量所代表的内存空间里面存放的地址给赋值到了新变量,实际指向的数据依然是同一份数据
深拷贝:
深拷贝的原理其实就是在进行对象复制的时候,人为的去索引引用所指向的真正数据,然后新建一个新的内存地址去存放浅拷贝出来的真正数据,然后让新变量指向这个人为生成的数据的地址
var a = {x:1}; var b = {}; b.x = a.x; b.x = 2; console.log(a,b); //{x:1} {x:2}
当然,在实际使用中,我们不可能依次去复制
深拷贝的几种方法:
1.JSON内置的方法
var a = {x:1}; var b = JSON.parse(JSON.stringify(a)); console.log(b); //{x:1} b.x = 2; console.log(b); //{x:2} console.log(a); //{x:1}
ps:该方法原理是将对象转换成JSON字符串,再转换回来,json字符串转换为对象的时候,会自己去构建新的内存地址存放数据
缺点:如果对象属性为function,因为JSON格式字符串不支持function,在构建的时候会自动删除
var a = {x:1, y: function() {}}; var b = JSON.parse(JSON.stringify(a)); console.log(b); //{x:1}
2.Object内置方法assign
var a = {x:1}; var b = Object.assign({}, a); console.log(b); //{x:1} b.x = 2; console.log(b); //{x:2} console.log(a); //{x:1}
ps:该方法原理是Object.assign方法实际上是对对象进行拼接, 将后续对象的内容插入到第一个参数指定的对象,不会修改第一个参数之后的对象,而我们将第一个对象指定为一个匿名空对象,实现深拷贝
缺点:对象嵌套层次过深,超过2层,就会出现浅拷贝的状况,比如echarts组件的option对象
var a = {x: {y: 1}}; var b = Object.assign({}, a); b.x.y = 2; console.log(b); //{x: {y: 2}} console.log(a); //{x: {y: 2}}
3.递归方法实现深拷贝
function ObjCopy(obj) { var tmp_obj; if(typeof obj == 'object') { if(obj instanceof Array) { tmp_obj = []; } else { tmp_obj = {}; } } else { return obj; } for (var i in obj) { if (typeof obj[i] != 'object') { tmp_obj[i] = obj[i]; } else if (obj[i] instanceof Array) { tmp_obj[i] = []; for (var j in obj[i]) { if (typeof obj[i][j] != 'object') { tmp_obj[i][j] = obj[i][j]; } else { tmp_obj[i][j] = ObjCopy(obj[i][j]); } } } else { tmp_obj[i] = ObjCopy(obj[i]); } } return tmp_obj; }
var a = {x: {y: {z: 1}}, m: function() {console.log(1);}}; var b = ObjCopy(a); console.log(b); //{x: {y: {z: 1}}, m: function() {console.log(1);}} b.x.y.z = 2; console.log(b); //{x: {y: {z: 2}}, m: function() {console.log(1);}} console.log(a); //{x: {y: {z: 1}}, m: function() {console.log(1);}}
总结:如果在没有function的情况下,可以直接使用JSON方式,如果在拷贝层次不超过3层的情况下,可以使用Object.assign方式,否则只能通过自己实现深拷贝