深拷贝和浅拷贝

区别:浅拷贝只是增加一个指针指向已存在的内存地址,仅仅是指向被复制的内存地址,如果原地址发生改变,那么浅拷贝出来的对象也会相应的改变。深拷贝是增加了一个指针并且申请了一个新的内存,使这个指针指向这个新的内存。

简单点来说,就是假设B复制了A,当修改A时,看B是否会发生变化,如果B也跟着变了,说明这是浅拷贝,如果B没变,那就是深拷贝。

1.如果是基本数据类型,名字和值都会存储在栈内存中。

var a = 1;
b = a; // 栈内存会开辟一个新的内存空间,此时b和a都是相互独立的
b = 2;
console.log(a); // 1
//当然,这也算不上深拷贝,因为深拷贝本身只针对较为复杂的object类型数据。

2.如果是引用数据类型,名字存在栈内存中,值存在堆内存中,但是栈内存会提供一个引用地址指向堆内存中的值。比如浅拷贝

let a = [1,2,3];
b = a;
b[0] = 4;
console.log(b); //[4, 2, 3]
console.log(a); //[4, 2, 3]
当b=a进行拷贝时,其实复制的是a的引用地址,而并非堆里面的值。
那,要是在堆内存中也开辟一个新的内存专门为b存放值,就像基本类型那样,岂不就达到深拷贝的效果了。
3.实现浅拷贝的方法
(1)直接用=赋值
let a=[0,1,2,3,4],b=a;
console.log(a===b);
a[0]=1;
console.log(b); //[1, 1, 2, 3, 4]
console.log(a); //[1, 1, 2, 3, 4]
(2)Object.assign()方法
var obj = {
    a: 1,
    b: 2
}
var obj1 = Object.assign(obj);
obj1.a = 3;
console.log(obj.a) // 3
(3)for...in只循环第一层
// 只复制第一层的浅拷贝
function simpleCopy(obj1) {
   var obj2 = Array.isArray(obj1) ? [] : {};
   for (let i in obj1) {
     obj2[i] = obj1[i];
   }
   return obj2;
}
var obj1 = {
   a: 1,
   b: 2,
   c: {
         d: 3
      }
}
var obj2 = simpleCopy(obj1);
obj2.a = 3;
obj2.c.d = 4;
alert(obj1.a); // 1
alert(obj2.a); // 3
alert(obj1.c.d); // 4
alert(obj2.c.d); // 4
4.实现深拷贝的方法
(1)通过JSON.parse(JSON.stringify())对象来实现深拷贝。
弊端: 无法实现对对象中方法的深拷贝,如果obj里有函数或者undefined,则序列化的结果会把函数或 undefined丢失;
let a = [{name:'cd',age:9},{name:'as',age:12}];
b = JSON.parse(JSON.stringify(a));
b[0].name = 'qq';
console.log(a); //[{name:'cd',age:9},{name:'as',age:12}]
console.log(b); //[{name:'qq',age:9},{name:'as',age:12}]
const test = {
    name: 'a',
    date: function hehe() {
      console.log('fff')
    },
};
const copyed = JSON.parse(JSON.stringify(test));
test.name = 'test'
console.error(test, copyed)
(2)通过jQuery的extend方法实现深拷贝。
var array = [1,2,3,4];
var newArray = $.extend(true,[],array);// true为深拷贝,false为浅拷贝
newArray[0]=9;
console.log(newArray); //[9, 2, 3, 4]
console.log(array); //[1, 2, 3, 4]
(3)采用递归去拷贝所有层级属性。
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); //[2, 2, 3, 4]
console.log(b); //[1, 2, 3, 4]
(4)使用扩展运算符实现深拷贝。
// 当value是基本数据类型,比如String,Number,Boolean时,是可以使用拓展运算符进行深拷贝的
// 当value是引用类型的值,比如Object,Array,引用类型进行深拷贝也只是拷贝了引用地址,所以属于浅拷贝
var car = {brand: "BMW", price: "380000", length: "5米"}
var car1 = { ...car, price: "500000" }
console.log(car1); // { brand: "BMW", price: "500000", length: "5米" }
console.log(car); // { brand: "BMW", price: "380000", length: "5米" }
(5)如果对象的value是基本类型的话,也可以用Object.assign来实现深拷贝,但是要把它赋值给一个空对象。
var obj = {
    a: 1,
    b: 2
}
var obj1 = Object.assign({}, obj); // obj赋值给一个空{}
obj1.a = 3;
console.log(obj.a); // 1
let a = [{name:'cd',age:9},{name:'as',age:12}];
let b = _.cloneDeep(a);
b[0].name = 'qq';
console.log(a);
console.log(b);
(7)手动实现深拷贝。
let obj1 = {
   a: 1,
   b: 2
}
let obj2 = {
   a: obj1.a,
   b: obj1.b
}
obj2.a = 3;
alert(obj1.a); // 1
alert(obj2.a); // 3

posted @ 2021-11-22 10:21  小新没蜡笔哦  阅读(496)  评论(0编辑  收藏  举报