js深拷贝,面试必问的,八说了,直接上菜~
使用递归方式进行深拷贝
let deepClone = (initalObj) => {
const obj = {};
if(typeof initalObj !== 'object'){
return initalObj
}
for (const key in initalObj) {
if (typeof initalObj[key] === 'object') {
//对数组特殊处理
if (Array.isArray(initalObj[key])) {
//用map方法返回新数组,将数组中的元素递归
obj[key] = initalObj[key].map(item => this.deepClone(item))
} else {
//递归返回新的对象
obj[key] = this.deepClone(initalObj[key]);
}
} else if (typeof initalObj[key] === 'function') {
//返回新函数
obj[key] = initalObj[key].bind(obj);
} else {
//基本类型直接返回
obj[key] = initalObj[key];
}
}
return obj;
}
const obj = {
a: 1,
b: {},
c: { d: {}, g: () => {} },
e: () =>{},
f: function () {}
}
const newObj = deepClone(obj);
newObj.a === obj.a //true
newObj.b === obj.b //false
newObj.c === obj .false //false
newObj.c.d === obj.c.d //false
newObj.c.g === obj.c.g //false
newObj.e === obj.e //false
newObj.f === obj.f //false
-
递归运行效率低,次数过多的话容易造成栈溢出。 -
比较常用!兼容性好!
通过JSON序列化实现深拷贝
序列化后再反序列化。
function Clone(obj) {
var Copyobj = JSON.stringify(obj),
//json字符串转json对象
objClone = JSON.parse(Copyobj);
return objClone;
}
注意,这种方法容易出很多问题,实际并不常用!
-
如果obj里有RegExp、Error对象,则序列化的结果将只得到空对象
-
如果obj里面有时间对象,则JSON.stringify后再JSON.parse的结果,时间将只是字符串的形式。而不是时间对象
-
如果obj里有函数,undefined,则序列化的结果会把函数或 undefined丢失
-
如果obj里有NaN、Infinity和-Infinity,则序列化的结果会变成null
-
无法处理function,无法处理循环引用对象
lodash函数库实现深拷贝
var abj={
a:1,
b:2
}
var copyobj = lodash.cloneDeep(abj)
这个没啥好说的,就是调用库函数罢了,原理和第一个一样。
使用jq(extend)方法实现深拷贝
var obj= {
a:10,
b:function (){
console.log(this.a)
}
};
var newObj = $.extend(true,{},obj);
这个也没啥好说的,就是调用库函数…啊这
其他补充
slice()和concat()
使用slice、concat方法并不是真正的深拷贝!
它们只会复制第一层,而到了第二层及其之后,只会复制引用地址了!
使用方法如下:
-
对于数组类型,可以使用slice(start, end)方法,返回一个新的数组。var arr1 = arr.slice(0); -
数组类型还可以使用concat()方法,var arr1 = arr.concat();
object.assign()
var obj1 = { a: 0 , b: { c: 0}};
var obj2 = Object.assign({}, obj1);
当对象中只有一级属性,没有二级属性的时候,此方法为深拷贝
如果是有多层嵌套呢?
var obj1 = {
a: 1,
b: 2,
c: ['a','b','c']
}
var obj2 = Object.assign({}, obj1);
obj2.c[1] = 5;
console.log(obj1.c); // ["a", 5, "c"]
console.log(obj2.c); // ["a", 5, "c"]
可以看到对于一层对象来说是没有任何问题的,但是如果对象的属性对应的是其它的引用类型的话,还是只拷贝了引用,修改的话还是会有问题。
所以可知,对象中有对象的时候,此方法在二级属性以后就是浅拷贝。
总结
从原理上来说,只有以下两种方法是无论有多少层嵌套都能实现真正的深拷贝。
-
自定义递归方法 -
json序列化
但是json序列化容易出bug,所以实际编写工具函数时,都会用第一种方法。
原文始发于微信公众号(豆子前端):[js基础]深拷贝的方法
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/56736.html