关注公众号 前端人,回复“加群”
添加无广告优质学习群
今天的题目介绍:
【虾皮一卷#03题】,每周题目周六统一录入文末小程序中!
深拷贝和浅拷贝的区别
深拷贝在于引用类型的时候,浅拷贝只复制地址值,实际上还是指向同一堆内存中的数据,深拷贝则是重新创建了一个相同的数据,二者指向的堆内存的地址值是不同的。这个时候修改赋值前的变量数据不会影响赋值后的变量。
深拷贝实现
1.通过递归方式实现深拷贝
function deepClone(obj) {
var target = {};
for(var key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) {
if (typeof obj[key] === 'object') {
target[key] = deepClone(obj[key]);
} else {
target[key] = obj[key];
}
}
}
return target;
}
2.通过json的方式实现
function (obj) {
let tmp = JSON.stringify(obj);
let result = JSON.parse(tmp);
return result;
}
3.通过Object.create()实现
function deepCopy(obj) {
var copy = Object.create(Object.getPrototypeOf(obj));
var propNames = Object.getOwnPropertyNames(obj);
propNames.forEach(function(name) {
var desc = Object.getOwnPropertyDescriptor(obj, name);
Object.defineProperty(copy, name, desc);
});
return copy;
}
var obj1 = { a: 1, b: {bc: 50, dc: 100, be: {bea: 1}} };
var obj2 = deepCopy(obj1);
console.log(obj2)
obj1.a = 20;
console.log(obj1)
console.log(obj2)
//Object {a: 1, b: Object}
//Object {a: 20, b: Object}
//Object {a: 1, b: Object}
浅拷贝
如果我们要复制对象的所有属性都不是引用类型时,就可以使用浅拷贝,实现方式就是遍历并复制,最后返回新的对象。
function shallowCopy(obj) {
var copy = {};
// 只复制可遍历的属性
for (key in obj) {
// 只复制本身拥有的属性
if (obj.hasOwnProperty(key)) {
copy[key] = obj[key];
}
}
return copy;
}
如上面所说,我们使用浅拷贝会复制所有引用对象的指针,而不是具体的值,所以使用时一定要明确自己的需求,同时,浅拷贝的实现也是最简单的。
JS内部实现了浅拷贝,如Object.assign(),其中第一个参数是我们最终复制的目标对象,后面的所有参数是我们的即将复制的源对象,支持对象或数组,一般调用的方式为
var newObj = Object.assign({}, originObj);
这样我们就得到了一个新的浅拷贝对象。另外[].slice()方法可以视为数组对象的浅拷贝。
深拷贝出现递归循环怎么办?结束条件是什么?
问题描述
js对象clone是RIA编程中常用方法,但是对象属性之间的循环引用会导致clone的递归进入死循环。
js 代码
var a = {pa1:'av1',pa2:'av2'};
var b = {pb1:'bv1',pb2:'bv2'};
a.pa3 = b;
//b.pb3 = a;
var c = cloneobj(a);
如果不包含注释掉的一行,clone是可以正常进行的。
但是如果引入这一行,即出现了js对象属性的循环引用,clone将进入递归的死循环。
现象
浏览器能够很好的处理这种错误,并抛出“too much recursion"错误,并定位到相应的代码行。(小声说一句:如果写个js死循环就把浏览器搞死了,B/S应用就没法混了)
办法
如何解决了,通常的办法就是限制递归的深度,例如DWR的‘DWRUtil.toDescriptiveString’
但是窃以为这个并非好的解决办法,因为了对应用造成极大的限制。
我的办法就是,在clone的过程中,记住每个已经clone的对象属性, 并且在对对象进行深度clone之前,首先检查是否已经clone过了,如果是,则返回已clone的引用即可。
因此只要放开示例代码的注释行" // return os[m];"就OK了。
参考资料
https://my.oschina.net/u/1440018/blog/543245 https://segmentfault.com/a/1190000011403163 https://segmentfault.com/a/1190000018193387
最后
关注公众号,置顶公众号
,鬼哥
每天解答一道大厂面试题,一起前端进阶
公众号里回复关键词 资料包
领取我整理的进阶资料包公众号里回复关键词 加群
,加入前端进阶群文章点个 在看
,支持一下把!