首先了解一下深拷贝与浅拷贝。
在js中把一个对象的属性与方法复制给另一个对象,或者是将父对象的属性拷贝给子对象,称为拷贝。
所谓浅拷贝(shallow copy),就是对象被拷贝时,实际上拷贝的只是该对象在内存中的位置指针(也可以说是该对象的引用)。在这种情况下,如果我们修改拷贝对象,就相当于修改了原对象。
深拷贝(deep copy)实现方式与浅拷贝基本相同,但是它避免了修改原对象这一问题。首先也是通过遍历对象的属性来进行拷贝操作,只是在遇到一个对象引用性的属性时,需要再次对其调用深拷贝函数,彻底拷贝该对象。
(此图源自http://www.haorooms.com/post/js_copy_sq)
浅拷贝的实现方式:
1.直接赋值(for...in)
function shallowCopy(p){
var c={};
for(var i in p){
c[i]=p[i];
}
return c;
}
测试:
2.ES6的对象新方法Object.assign()
Object.assign(target,source1,source2),用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象(target)。该方法第一个参数是目标对象,后面的参数都是源对象。
注:当对象只有一层时,Object.assign()实现的是深拷贝。
深拷贝的实现方式:
1.当对象只有一层时,可以用ES6的对象新方法Object.assign()
2.递归
function deepCopy(p,c){
c=c || {};
for(var i in p){ //遍历一个对象的可枚举属性(包括对象本身的所有可枚举属性,以及对象从其构造函数原型中继承的属性)
if(p.hasOwnProperty(i)){ //检测i是不是对象p本身的一个属性或对象,继承的属性不显示
if(typeof p[i] ==='object'){
c[i]=Array.isArray(p[i]) ? [] : {}; //区分Array对象和Object对象
deepCopy(p[i],c[i]);
}else{
c[i]=p[i];
}
}
}
return c;
}
测试:
3.先用JSON.stringify()转换成JSON格式,再用JSON.parse()转回对象
4.使用jQuery的$.extend(true,{},obj)
注:由于本次测试直接在Chrome控制台进行,需要支持jQuery,所以首先要在当前页面引入jQuery库:
var fileref=document.createElement('script');
fileref.setAttribute('type','text/javascript');
fileref.setAttribute('src','https://code.jquery.com/jquery-latest.js');
document.getElementsByTagName('head')[0].appendChild(fileref);
接着再执行$.extend()方法:
注:用jQuery的$.extend({},obj)可以实现对象的浅拷贝!!
5.使用函数库lodash的_.cloneDeep
首先,依旧是引入lodash库:
var fileref=document.createElement('script');
fileref.setAttribute('type','text/javascript');
fileref.setAttribute('src','https://cdn.bootcss.com/lodash.js/4.17.4/lodash.js');
document.getElementsByTagName('head')[0].appendChild(fileref);
注:实测中发现部分lodash库不具有_.cloneDeep()函数,因此注意版本为4.17.4
使用:
注:使用lodash库的_.clone()方法可实现浅拷贝