当前位置: 首页 > Web前端 > HTML

JS变量存储与深拷贝与浅拷贝

时间:2023-04-02 13:16:44 HTML

变量类型与存储空间栈内存与堆内存基本数据类型string、number、null、undefined、boolean、symbol(ES6新加入)变量值存储在栈中内存,并且可以直接访问和修改变量的值。没有基本数据类型的副本。比如不能修改值1的值。引用类型ObjectFunctionRegExpMathDate的值是一个对象,存放在堆内存中。栈内存中存储的变量是一个指针,指向堆内存中对应的地址。访问引用类型时,先从栈中取出对象的地址指针,然后从堆内存中获取需要的数据图形存储空间leta1=0;//栈内存leta2="thisisstring"//栈内存leta3=null;//栈内存letb={x:10};//变量b存在于栈中,{x:10}作为对象存在于堆中letc=[1,2,3];//变量c存在于栈中,[1,2,3]作为对象存在于堆中。引用类型的赋值leta={x:10,y:20}letb=a;b.x=5;控制台日志(a.x);//5深拷贝和浅拷贝深拷贝从内存中完全复制一个对象,从堆内存中开辟一个新的区域来存放新对象,修改新对象不会影响原对象的浅拷贝浅拷贝是按位拷贝一个对象,它创建一个新对象,该对象具有原始对象属性值的精确副本。如果属性是基本类型,则复制的是基本类型的值;如果属性是内存地址(引用类型),复制的是内存地址对象的赋值当我们将一个对象赋值给一个新的变量时,实际赋值的是该对象在栈上的地址,而不是堆上的数据。即两个对象指向同一个存储空间。无论哪个对象发生变化,实际上都是变化的存储空间的内容。因此,这两个对象是链接在一起的。浅拷贝Object.assign()三种常用的五种方法对比Object.assign()方法可以将源对象本身的任意数量的可枚举属性复制到目标对象中,然后返回目标对象。但是Object.assign()是浅拷贝Object.assign会从左到右遍历源对象(sources)的所有属性,然后用=赋值给目标对象(target)varobj={a:{a:"科比",b:39},b:1};varinitalObj=Object.assign({},obj);initalObj.a.a="韦德";initalObj.b=2;控制台日志(obj.a.a);//韦德console.log(obj.b);//1扩展运算符letobj={a:1,b:{c:1}}letobj2={...obj};obj.a=2;console.日志(对象);//{a:2,b:{c:1}}console.log(obj2);//{a:1,b:{c:1}}obj.b.c=2;控制台。日志(对象);//{a:2,b:{c:2}}console.log(obj2);//{a:1,b:{c:2}}Array.prototype.sliceslice()方法返回一个新的数组对象,它是原始数组的浅拷贝,由begin和end(不包括end)决定。原数组的基本类型不会变,引用类型会变。让arr=[1,3,{username:'kobe'}];让arr3=arr.slice();arr3[0]=0;arr3[2].username='wade'console.log(arr);Array.prototype.concat()letarr=[1,3,{username:'kobe'}];letarr2=arr.concat();arr3[0]=0;arr2[2].username='wade';console.log(arr);手写浅拷贝函数shallowCopy(src){vardst={};for(varpropinsrc){if(src.hasOwnProperty(prop)){dst[prop]=src[prop];}}returndst;}深拷贝常用方法JSON.parse(JSON.stringify())通过JSON.stringify实现深拷贝value中有function,undefined,symbol需要注意几点复制的对象.stringify()序列化后的JSON字符串中的键值对将消失。不可枚举的属性不可复制,对象的原型链不可复制。复制Date引用类型将变成一个字符串。复制RegExp引用类型将成为一个空对象。如果对象中包含NaN、Infinity和-Infinity,则序列化后的结果将变为null。对象的循环应用不可复制(即obj[key]=obj)letarr=[1,3,{username:'kobe'}];letarr4=JSON.parse(JSON.stringify(arr));arr4[2].username='邓肯';console.log(arr,arr4)$.extend(true,object,object1,);参考jQuery官方文档手写乞丐版深拷贝首先这个deepClone函数不能拷贝不可枚举的属性和Symbol类型。这里,只是对Object引用类型的值进行了循环迭代,而对于Array,Date,RegExp,Error,Function引用类型无法正确复制对象成环,即循环引用(例如:obj1.a=obj)functionclone(target){if(typeoftarget==='object'){让cloneTarget=Array.isArray(target)?[]:{};for(constkeyintarget){cloneTarget[key]=clone(target[key]);}返回克隆目标;}else{返回目标;}};升级版使用weekmap解决循环引用。Weekmappairkey是一个弱应用,也解决了垃圾回收的问题。functiondeepClone(target,map=newWeakMap()){if(typeoftarget==="object"){让cloneTarget=Array.isArray(target)?[]:{};如果(map.has(target))返回map.get(target);map.set(target,cloneTarget);for(letkeyintarget){cloneTarget[key]=deepClone(target[key],map);}返回克隆目标;}else{返回目标;}}将递归版本改为循环函数deepClone(data){constroot={}constloopList=[{parent:root,key:undefined,data:data}]while(loopList.length>0){constnode=loopList.pop()//从后面取,进入后面,进行深度优先搜索const{parent,key,data}=nodeletres=parentif(key!==undefined){//如果有key,说明上层的data[key]是一个对象,即传过来的数据是一个对象//说明需要复制父key数据,所以创建一个对象来复制toparent[key]res=parent[key]={}}for(letkeyindata){if(typeofdata[key]=='object'){loopList.push({parent:res,key:key,data:data[key]})}else{res[key]=data[key]}}}returnroot}帝王版深拷贝本实例来自ConardLi的github,源码地址:https://github.com/ConardLi/C...constmapTag="[对象地图]";constsetTag="[对象集]";constarrayTag="[对象数组]";constobjectTag="[对象对象]";constargsTag="[对象参数]";constboolTag="[对象布尔值]";constdateTag="[对象日期]";constnumberTag="[对象编号]";conststringTag="[对象字符串]";constsymbolTag="[对象符号]";consterrorTag="[对象错误]";constregexpTag="[对象RegExp]";constfuncTag="[objectFunction]";constdeepTag=[mapTag,setTag,arrayTag,objectTag,argsTag];functionforEach(array,iteratee){让索引=-1;constlength=array.length;while(++index{cloneTarget.add(clone(value,map));});返回克隆目标;}//克隆地图if(type===mapTag){target.forEach((value,key)=>{cloneTarget.set(key,clone(value,map));});返回克隆目标;}//克隆对象和数组constkeys=type===arrayTag?未定义:对象键(目标);forEach(keys||target,(value,key)=>{if(keys){key=value;}cloneTarget[key]=clone(target[key],map);});返回克隆目标;}constmap=newMap();map.set("键","值");map.set("ConardLi","code秘密花园");constset=newSet();set.add("ConardLi");set.add("密密花园密码");consttarget={field1:1,field2:undefined,field3:{child:"child"},field4:[2,4,8],空:null,map,set,bool:newBoolean(true),num:newNumber(2),str:newString(2),symbol:Object(Symbol(1)),date:newDate(),reg:/\d+/,error:newError(),func1:()=>{console.log("密码秘密花园");},func2:function(a,b){返回a+b;}};常量结果=克隆(目标);控制台日志(目标);控制台日志(结果);/5b5dcf...https://juejin.im/post/5d6aa4...https://juejin.im/post/59ac1c...