写这个系列文章的初衷是“让每一位前端工程师掌握高频知识点,助力工作”。相信老手都会遇到assignment,shallowcopy,deepcopy,尤其是shallowcopy和deepcopy,不管是学习还是面试。两次遇到这个问题记忆犹新:一次是系统写了个bug,是因为对深浅拷贝理解不清晰;百度面试。1赋值赋值是指直接将一个变量赋值给另一个变量,如下所示:consta1=10;consta2=a1;console.log(a2);//10constb1={m:10,n:20};constb2=b1;console.log(b2);//{m:10,n:20}如上所示,赋值是将一个值赋值给另一个值,赋值过程中需要注意两点:对于基本类型赋值是在栈内存中开辟新的存储区,用于存放新的变量;对于引用类型赋值,就是引用类型的地址,在堆中指向同一个值。2浅拷贝2.1基本实现浅拷贝是指遍历一次对象,将对象的属性赋值给另一个对象。在这个过程中,如果属性值是基本类型,则复制基本类型的值;如果该值是引用类型,则复制内存地址。functionclone(source){if(!(typeofsource==='object'&&source!==null)){returnsource;}consttarget={};//只考虑Object类型for(let[key,value]ofObject.entries(源)){目标[键]=值;}返回目标;}constobj={a:10,b:{m:20}};constcloneObj=克隆(obj);cloneObj.a=20;cloneObj.b.m=30;console.log(obj);//{a:10,b:{m:30}}console.log(cloneObj);//{a:20,b:{m:30}}以上是一个简单的浅显copy过程中可以看到,浅拷贝就是将原对象中的值遍历一层,然后赋值给新的对象。遍历过程中可以得到如下信息:当遍历到a属性时,它是一个基本类型,所以会在栈内存中创建一个新的存储区来存放变量。遍历到b属性时,因为是引用类型,所以会在栈内存中存放堆地址,从而指向堆内存中的同一个对象。当对浅拷贝创建的对象cloneObj中的a属性和b.m属性进行重新赋值时,可以发现a属性的值不一样了,但是b.m属性的值发生了变化,从而验证了上述1和2的分析。2.2进阶本章既然讲了浅拷贝,就得了解一下Object.assign()。该方法是一个合并对象的浅拷贝过程,将源对象(source)的所有可枚举属性复制到目标对象。2.2.1基础要实现一个功能,首先要了解一个功能。将不详细描述该方法的基本使用。这里有几个注意点:如果目标对象与源对象同名(或者多个源对象有同名属性),后一个属性会覆盖前一个属性;如果只有一个参数,Object.assign会直接返回参数。如果参数不是对象,则先转为对象,再返回;(注意:由于undefined和null不能转为对象,所以作为参数会报错)非对象参数出现在源对象的位置,这些参数会被转为Object,如果是不能转化为对象,会被跳过(所以undefined和null不会报错)。(注意:字符串会以数组的形式复制到目标对象,其他不会)只复制源对象自身的属性(不复制继承的属性),不复制不可枚举的属性;名为Symbol值的属性也将被Object.assign复制。2.2.2实施注意事项上面已经说明了。接下来,让我们实现Object.assign()。实现步骤如下:判断目标对象,不能为null或undefined;将目标转换为对象(防止字符串、数字等);获取后续源对象自身中的可枚举对象(包括Symbol),复制到目标对象中;返回处理后的目标对象;使用Object.defineProperty()将函数配置为Object的不可枚举挂载。functionObjectAssign(target,...sources){//判断第一个参数,不能是undefined或者nullif(target===undefined||target===null){thrownewTypeError('cannotconvertfirstargumenttoobject');}//转换firstparametertoanobjectconsttargetObj=Object(target);//复制源对象(source)自身的所有可枚举属性到目标对象(target)for(leti=0;i
