今天看到一个关于对象复制的demo, 需求是复制一份数据,之后修改里面num的值,数据结构如下:
var info = { "last_win":2, "open":1, "user_money":228, "win_info":[ { "uin":001, "name":"我是昵称我的昵称有12个字","num":12000 }, { "uin":002, "name":"我是昵称我的昵称","num":22000 }, { "uin":003, "name":"我是昵称","num":32000 }, { "uin":004, "name":"我是昵称我的昵称有12个字个字个字","num":42000 } ], "user_bet":["100000","2000","300000"], "total_bet":["100000000","200000","3000"] }
一、看到需求,脑海中应清楚几个点
1、复制一份之后修改,修改副本对原对象不能有改动。
2、复制的对象里面有数组,还要判断对象是不是数组。
3、修改副本。
二、理解对象拷贝
浅复制只会将对象的各个属性进行依次复制,并不会进行递归复制,而 JavaScript 存储对象都是存地址的,所以浅复制会导致原对象和复制之后的对象 指向同一块内存地址。
深复制则不仅将原对象的各个属性逐个复制出去,而且将原对象各个属性所包含的对象也依次采用深复制的方法递归复制到新对象上。
三、修改对象(浅拷贝)
var obj1 = {a:10, b:{d:40}, c:30}; //浅拷贝 function showdowCopy(obj){ var tempObj = {}; for(var key in obj){ tempObj[key] = obj[key]; } return tempObj; } var cloneObj = showdowCopy(obj1); cloneObj.b.d = 100000; console.log(obj1.b.d);//100000
浅拷贝之后,修改拷贝所得的对象,原对象也会改变;
结果:
console.log(info); console.log('------------上面是拷贝前的对象,下面是拷贝且修改的对象---------'); console.log(modifieData);
四、数组的复制的其他方法
数组提供了复制的API,比如
var arr1=[1,3,4,6]; //slcie() var arr2 = arr1.slice(0); //concat() var arr3 = arr1.concat();
!!!当数组内的元素为对象时候,还是引用复制,只能进行浅拷贝。
五、Object.assign()
方法可以把任意多个的源对象自身的可枚举属性拷贝给目标对象,然后返回目标对象。但是 Object.assign
是ES6的新函数。Object.assign()Object.assign()
进行的是浅拷贝。 只能处理一层的深拷贝;
var obj1 = { a: 10, b: 20, c: 30 }; var obj2 = Object.assign({}, obj1);
六、深拷贝的实现方式
1、递归
function deepClone(initalObj, finalObj){ var obj = finalObj || {}; for(var i in initalObj){ //避免相互引用情况 if(initalObj[i] === obj){ continue; } if(typeof initalObj[i] === 'object'){ obj[i] = Array.isArray(initalObj[i]) ? [] : {}; arguments.callee(initalObj[i], obj[i]); }else{ obj[i] = initalObj[i]; } } return obj; } var str = {}; var obj = {a:10, b:{c:20, d:[2,100]}} deepClone(obj, str); console.log(str); str.b.c = 1000000; console.log(obj); console.log(str);
function deepCopy(source) { var result = Array.isArray(source) ? [] :{}; //因为原始数据中有object对象和Array对象 for (var key in source) { if(Array.isArray(source[key])){ result[key] = deepCopy(source[key]); }else if(typeof source[key]==='object'){ result[key] = deepCopy(source[key]) }else{ result[key] = source[key] } } return result; } console.log(info));
2、jquery中的$.extend()
var obj2 = $.extend(true, {}, obj1); //第一个参数为true为深拷贝,false为浅拷贝
3、第三方函数库lodash
var _ = require('lodash'); var obj2 = _.cloneDeep(obj1);
4、 JSON.parse 和 JSON.stringify 就是把需要赋值的类型转为基本类型(字符串这些)而非引用类型来实现
// JOSN对象中的stringify可以把一个js对象序列化为一个JSON字符串,parse可以把JSON字符串反序列化为一个js对象 var deepClone = function(sourceObj) { if (!sourceObj || typeof sourceObj !== 'object') { console.log('您传入的不是对象!!'); return; } // 转->解析->返回一步到位 return window.JSON ? JSON.parse(JSON.stringify(sourceObj)) : console.log('您的浏览器不支持 JSON API'); };
七、补充-对象是不是数组类型的ployfill
if(!Array.isArray){ Array.isArray = function(arg){ return Object.prototype.toString.call(arg) === '[object Array]'; } }