想要了解JS中对象的浅拷贝和深拷贝,需要从它的数据类型说起。JavaScript中的数据类型一般说到JS的数据类型,都是指它的原始(Primitivetypes)数据类型(共6种):StringNumberBooleanSymbol(ES6新增)NullUndefined这些类型可以直接操作变量存储的实际值.另外,JS中还有引用数据类型:对象(Object)、数组(Array)、函数(Function)。在JS中,除了基本数据类型都是对象,数组是对象,函数是对象,正则表达式是对象,日期也是对象……栈(stack)和堆(heap)栈是自动分配的内存空间,由系统自动释放;而堆是动态分配的内存,大小不确定。基本数据类型是指存放在栈中的简单数据段。数据大小确定了,就可以分配内存空间大小了。它们是直接按值存储的,所以可以直接按值访问:vara=10;变量b=a;b=20;console.log(a);//10console.log(b);//20重新分配的b不影响a的值。引用类型是存储在堆内存中的对象。变量其实是一个保存在栈内存中的指针(保存的是堆内存中的引用地址),这个指针指向堆内存。varobj1=newObject();varobj2=obj1;obj2.description="HelloWorld";console.log(obj1.name);//HelloWorld表示这两个引用数据类型指向同一个堆内存对象。引用传递和值传递在拷贝变量的过程中,对象的拷贝是引用传递,基本类型是值传递。将保存原始值的变量复制到另一个变量时,会将原始值的副本分配给新变量。之后,这两个变量就完全独立了,它们只是具有相同的值。引用值:当将一个保存对象内存地址的变量复制到另一个变量时,内存地址会被赋值给新的变量,也就是说两个变量都指向堆内存中的同一个对象,其中Any一个人所做的更改将反映在另一个人身上。浅拷贝当我们要拷贝一个对象时,如果它的属性是一个对象或者数组,这时候我们传递的只是一个地址。因此,当子对象访问该属性时,会根据地址回溯到父对象指向的堆内存,即父子对象关联,两者的属性值会指向同一个内存空间。constobj={name:"bird",abilities:["fly","sing"]}functioncopy(target){varobjNew={};for(variintarget){objNew[i]=target[i]}returnobjNew;}constobjCopy=copy(obj)console.log(objCopy)//{名称:“鸟”,能力:[“飞”,"sing"]}objCopy.name="bird01"//修改原始类型的属性console.log(objCopy)//{name:'bird01',abilities:["fly","sing"]}objCopy.abilities.push("layeggs")//修改引用类型控制台的属性.log(objCopy)//{name:'bird01',abilities:["fly","sing",'layeggs']}console.log(obj)//{name:'bird',abilities:["fly","sing",'layeggs']}可以看到obj的abilities属性随着objCopy的变化而变化,并且这两个对象之间存在关联。需要注意的是,Object.assign()或SpreadOperator都是浅拷贝:constobj={name:"bird",abilities:["fly","sing"]}constobjCopy=Object.assign({},obj)//{name:"bird",abilities:["fly","sing"]}objCopy.abilities.push("layegg")console.log(obj)//{name:"bird",abilities:["fly","sing","layegg"]}constobjCopy2={...obj}//{name:"bird",abilities:["fly","sing","layegg"]}objCopy2.abilities.pop()console.log(obj)//{name:"bird",abilities:["fly","sing"]}这样的联想往往不是我们想看到的,所以才会有深拷贝。深拷贝可以使用JSON.parse/stringify来拷贝属性包含数组的情况:consta={arr:["Google","Baidu"]}constclone=JSON.parse(JSON.stringify(a))clone.arr.pop()console.log(a)//{arr:["Google","Baidu"]}可以看出clone的属性变化不再和a关联。但是对于其他类型的属性,在处理过程中可能会丢失:consta={string:'string',number:123,bool:false,nul:null,date:newDate(),//stringifiedundef:undefined,//lostinf:Infinity,//forcedto'null're:/.*/,//lost}所以使用一些第三方库是个不错的选择,比如:lodash-cloneDeep;可以通过lodash.clonedeep模块单独导入,如果您还没有使用在不久的将来提供深度克隆功能的库,这可能是您的最佳选择也许您可以使用structuredClone2021更新:structuredCloneglobalfunctioniscomingtobrowsers、Node.js和Deno。关联
