数据深拷贝是实际项目中你总有一天或者必然会遇到的问题,甚至很多人可能对这两个概念并不是很清晰。简单来说,深拷贝就是把一条数据A复制出来个副本B,修改副本B数据并不会影响原来数据A,浅拷贝则反之,修改数据B会影响到原来的A数据。下面总结下有些处理深拷贝的方法(下列方法demo均来自于互联网,本文章主要用于总结归档,方便后人查阅)
浅拷贝
let a=[0,1,2,3,4], b=a;console.log(a===b);a[0]=1;console.log(a,b);
为什么会出现上面这种情况?
那么这里,就得引入基本数据类型与引用数据类型的概念了。面试常问,基本数据类型有哪些,number,string,boolean,null,undefined,symbol以及未来ES10新增的BigInt(任意精度整数)七类。引用数据类型(Object类)有常规名值对的无序对象{a:1},数组[1,2,3],以及函数等。
实现简单的深拷贝
1、slice和concat
这两个方法特性是将原来的数据产生一个副本,不会去改变原来的数据,但它有一定的局限性,如果数据是基本数据类型,那是可以的,否则,就会有问题。
var a= [0,1,2,3,4];var b= a.slice(0); // 通过slice方法,参数为0,意味着拷贝数组arr1的0 - 最后一位b[1] = "9";
2、Object.assign()方法
这个方法和上面的slice和concat方法有同样的弊端
var Jack ={ code:'0001', name:'张三', assing:function () { alert('张三签到'); }, car:{ name:'路虎', type:'SVR' }} var Tom = Object.assign({},Jack);Tom.name = '赵四';console.log(Jack);console.log(Tom);Tom.car.name='宝马';console.log(Jack);console.log(Tom);
3、Json.parse(Json.stringify(obj))方式
我太难了,看了上面几种方法,都不能达到要求,那么Json.parse又会如何呢?该方法成功实现了嵌套属性的深拷贝,但是原对象中的assign()方法丢失了。这是因为JSON.stringify()方法将对象转化为字符串,但只会处理简单属性和简单属性数组,constructor属性丢失了。也就是说他中间变换了形态,从对象—>字符串—>对象,最终把原对象该有的自身方法弄丢了,如果你不介意,自然是可以的,因此,除非对象只有简单属性,没有constructor信息,才能使用Json.parse(Json.stringify(obj))做深拷贝。
var Alex = JSON.parse(JSON.stringify(Jack));Alex.name='王五';Alex.car.name='劳斯莱斯';console.log(Jack);console.log(Alex);
4、es6中的 Object.create()方法
function deepClone(initalObj, finalObj) { var obj = finalObj || {}; for (var i in initalObj) { var prop = initalObj[i]; // 避免相互引用对象导致死循环,如initalObj.a = initalObj的情况 if(prop === obj) { continue; } if (typeof prop === 'object') { obj[i] = (prop.constructor === Array) ? [] : Object.create(prop); } else { obj[i] = prop; } } return obj;}
那么到底如何实现复杂的数据结构深拷贝?
自己封装个简单方法是个不错的选择
function deepClone(obj) { let objClone = Array.isArray(obj) ? [] : {}; if (obj && typeof obj === "object") { for (key in obj) { if (obj.hasOwnProperty(key)) { //判断ojb子元素是否为对象,如果是,递归复制 if (obj[key] && typeof obj[key] === "object") { objClone[key] = deepClone(obj[key]); } else { //如果不是,简单复制 objClone[key] = obj[key]; } } } } return objClone;}var obj1 = { a: 1, b: [{ x: 1, y: 2 }], c: { d: [{bb: 100}] }}var obj2 = deepClone(obj1);obj2.a = 3;obj2.b[0].x = 10;obj2.b[0].y = 20;obj2.c.d[0].bb = 200;console.log(obj1,obj2)
借助函数库lodash实现深拷贝
这个方法库特别强大,可以极大的提高工作中处理数据效率。
var objects = [{ 'a': 1 }, { 'b': 2 }]; var deep = _.cloneDeep(objects);console.log(deep[0] === objects[0]);// => false
小结
说了这么多,了解深拷贝也不仅仅是为了应付面试题,在实际开发中也是非常有用的。例如后台返回了一堆数据,你需要对这堆数据做操作,但多人开发情况下,你是没办法明确这堆数据是否有其它功能也需要使用,直接修改可能会造成隐性问题,深拷贝能帮你更安全安心的去操作数据,根据实际情况来使用深拷贝,大概就是这个意思。
微信号:gh_dcd05cdf3c3e扫码关注我们,获取最新资讯