js深浅拷贝的理解
说起js的深浅拷贝不得不提起的是js的数据类型
- 基本数据类型 :undfined string boolean null number
- 引用数据类型:array object function
基本数据类型存储在栈内存中
变量 | 值 |
---|---|
a | 1(栈内存) |
b | (指针) |
var a=1;var b = a a=3;console.log(a,b)//3,1
如上代码所示:
1.深拷贝与浅拷贝的区别
如何区分深拷贝与浅拷贝,简单点来说,就是假设B复制了A,当修改A时,看B是否会发生变化,如果B也跟着变了,说明这是浅拷贝,被人牵着鼻子走,如果B没变,那就是深拷贝,自立更生。
引用数据类型存储在堆内存中
var b={name:"张三",age:"25"}
var newobj = b;
b.name="李四"
"李四"
console.log(b,newobj)
//{name: "李四", age: "25"} {name: "李四", age: "25"}
为什么会出现上述的结果呢?
因为newobj=b时只是复制了b在栈内存中的指针,而指针执行的只是堆内存中的一个地址,通过赋值给newobj 等于b和newobj都共用这块内存。
堆内存 |
---|
(b) {name:“zhangsan”,age:“25”} |
数组深拷贝:尝试过 slice concat 但只是拷贝了一层,并没有实现真正的拷贝
对象深拷贝:尝试过 Object.assign
使用Object.assign方式只拷贝了对象的第一层, 第二层或之后都只拷贝了指针;修改obj2第二层,obj1还是会跟着改变
那么怎么实现深拷贝呢?
深拷贝
1.递归
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;
}
let a=[1,2,3,4],b=deepClone(a);
a[0]=2;
console.log(a,b);
2.JSON 对象的 parse 和 stringify都是深拷贝
这种方法能正确处理的对象只有 Number, String, Boolean, Array, 扁平对象,即那些能够被 json 直接表示的数据结构。RegExp对象是无法通过这种方式深拷贝。
var obj = {name:'zhangsan',age:23,company : { name : '阿里', address : '杭州'} };
var newobj = JSON.parse(JSON.stringify(obj));
obj.company.name = "阿里巴巴";
obj.name = "zhangsan1";
console.log(obj);//{name:'zhangsan1',age:23,company : { name : '阿里巴巴', address : '杭州'} }
console.log(newobj);// {name:'zhangsan',age:23,company : { name : '阿里', address : '杭州'} }
3.lodash函数库实现深拷贝
lodash很热门的函数库,提供了 lodash.cloneDeep()实现深拷贝
4.通过jQuery的extend方法实现深拷贝
var array = [1,2,3,4];
var newArray = $.extend(true,[],array);
5.使用Object.create()方法
直接使用var newObj = Object.create(oldObj),可以达到深拷贝的效果。
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;
}