js中的深克隆(深拷贝)和浅克隆(浅拷贝)

    技术2022-07-11  85

    数据类型

    我们都知道我们的数据类型分为两大类:

    基本的数据类型有:number,string,boolean,null,undefined,symbol,引用数据类型(Object)有:{},[] 和函数

    数据类型的存储方式

    基本数据类型 基本类型–名值存储在栈内存中,例如let a=1; 当 b=a 进行赋值时,栈内存会开辟出一个新的内存存储 b 所以当你此时修改a=2,对b并不会造成影响,但这也算不上深拷贝,因为深拷贝本身只针对较为复杂的 object类型数据。引用数据类型 引用数据类型–名存在栈内存中,值存在于堆内存中,但是栈内存会提供一个引用的地址指向堆内存中的值 例如: let a=[0,1,2,3,4], b=a; console.log(a===b); a[0]=1; console.log(a,b);

    当b=a进行拷贝时,其实复制的是a的引用地址,而并非堆里面的值。 而当我们a[0]=1时进行数组修改时,由于a与b指向的是同一个地址,所以自然b也受了影响,这就是所谓的浅拷贝了。 那,要是在堆内存中也开辟一个新的内存专门为b存放值,就像基本类型那样,岂不就达到深拷贝的效果了

    浅拷贝深拷贝描述

    浅克隆:直接将存储在栈中的值赋值给对应变量,如果是基本数据类型,则直接赋值对应的值,如果是引用类型,则赋值的是地址

    基本数据类型是直接存储在栈内存中的,而引用数据类型,则仅仅是把地址存储在栈内存中,真正的数据是存储在堆内存中的,赋值操作时,仅仅把地址进行了赋值。

    深克隆:就是把数据赋值给对应的变量,是拷贝对象各个层级的属性,在内存中开辟一块新内存,将原对象中的所有值全部复制过去,与原对象完全脱离,修改新对象中的属性值不会影响原对象、

    浅克隆举例

    let a = "xu"; let b = a; alert( b ); // 'xu' a = "ke"; alert( b ); // 'xu' // 在这段代码中,把a赋值给b,当a的值发生变化时,并不影响b let arr1 = [1, 2, 3]; let arr2 = arr1; console.log( arr2 ); // [ 1, 2, 3] arr1[0] = 2; console.log( arr2 ); // [ 2, 2, 3] // 在这段代码中,把arr1赋值给arr2,当arr1的值改变时,arr2对应的值也会改变
    浅克隆实现方法:
    es6 拓展运算符 const obj ={ name:"xuke", age:22 } const obj2 = {...obj} console.log(obj2.name) //xuke for循环遍历 let obj = { name:"xuke", age:22 } function clone(obj ){ const result = {} for(let key in obj){ result[key] = obj[key]; } return result } let obj2 = clone(obj) obj.name = "xiannv" console.log(obj2.name) //xuke console.log(obj2==obj) //false

    obj2不会受obj的影响,因为被克隆的都是·基本数据类型,被存到栈中的东西,

    如果obj中存在引用数据类型的话:

    let obj ={ name:"xuke", age:22, hobby:{ first:"eat", second:"sleep" } } function clone(obj ){ const result = {} for(let key in obj){ result[key] = obj[key]; } return result } let obj2 = clone(obj) obj.hobby.first= "play" console.log(obj2.hobby.first) //play console.log(obj2==obj) //false

    我们可以看到obj2复制的obj中含有引用数据类型,我们修改了obj中的引用数据类型时,obj2中的也会改变,数据在复制的时候是把obj中的引用数据类型的地址一起复制过去了,所以obj和obj2使用的是一个地址,所以obj2会受影响,我们想要不受影响就要使用深克隆的方法。

    深克隆实现方法:
    JSON.parse(JSON.stringify())实现深度克隆 let obj ={ name:"xuke", age:22, hobby:{ first:"eat", second:"sleep" } } let obj2 = JSON.parse(JSON.stringify(obj)) obj.hobby.first= "play" console.log(obj2.hobby.first) //eat console.log(obj2==obj) //false

    JSON.parse(JSON.stringify())实现深度克隆的弊端:

    1.对象中的方法不能进行copy,会自动忽略 2.对象中的Date时间不能进行copy, JSON.stringify方法会将日期自动转换为常规日期格式

    3.正则表达式不能copy , JSON.stringify方法会将正则变为空对象

    解决方法,用方法2将这些过滤掉: 2. 用递归实现深克隆

    let obj ={ name:"xuke", age:22, hobby:{ first:"eat", second:"sleep" } } function clone(obj ){ // 过滤特俗情况 if(obj===null) return obj if(typeof obj !=='object') return obj if(obj instanceof RegExp){ return new RegExp(obj) } if(obj instanceof Date){ return new Date(obj) } let newObj = new obj.constructor for(let key in obj){ if (obj.hasOwnProperty(key)) { newObj[key] = clone(obj[key] ) } } return newObj } let obj2 = clone(obj) obj.hobby.first= "play" console.log(obj2.hobby.first) //eat console.log(obj2==obj) //false

    使用:当copy源中没有引用类型,方法,正则,日期等值,只是普通的数据类型时,我们就可以用浅拷贝的方法,反之用深拷贝

    Processed: 0.010, SQL: 9