浅析JS赋值与深浅拷贝
说到深浅拷贝,那在这就不得不提一下内存和数据类型了。
在JS当中,数据类型分为基本数据类型和引用类型,其中基本数据类型共六种(string,number,boolean,undefined,null,symnol),引用类型为Object(细分可分为Array、object、date......)。
那么在来说一下内存,内存分为栈内存和堆内存,其中栈内存用来存储基本数据类型和引用类型的地址,而堆内存则存储引用数据类型。
一、赋值
什么是赋值呢,其实赋值分为两种,一种是传值,还有一种是传址,顾名思义,前者传的是基本数据类型的值,比如变量的值、字符串或者是undefined,而后者传递的是引用类型的地址。简单来说就是在栈内存中重新开辟一块新的空间,将需要的值复制一份,那有的同学就要说了,这不就是拷贝么?其实不然,对于传值来说,如果将变量a赋值给变量b,复制的仅仅是值,当你改变b的时候,a不受影响,如图:
但对于传址来说,由于复制的是引用类型的地址,那么不管复制多少次,他指向的堆内存中的内存块没有变,也就是说,复制出来的两个地址指向同一个内存块,不管改变哪个对象,他们的值都会一起改变,如图:
二、拷贝
什么是拷贝?拷贝和赋值究竟有何不同?简单来说,二者最根本的不同就在于操作的对象不同,赋值操作的是基本数据类型,而拷贝操作的是引用数据类型,究其本质就是,前者是对栈内存的数据进行的操作,后者是对堆内存的数据进行的操作。
var obj={name:"tom",sex:"man",obj1:{age:15}}
2.1浅拷贝
所谓浅拷贝,也就是只拷贝对象的第一层,即只拷贝最外层的基本数据类型,对于对象中的其他引用类型则只拷贝其地址,也就是说,以上面的obj为例,浅拷贝过来的应该是:
{name:"tom",sex:"man",obj1:{obj1的地址}}
到此为止,你可以随意更改name、sex,源数据不会受到影响,但当你更改obj1的内容时,源数据中的obj1也会随之发生改变
2.2深拷贝
深拷贝理解起来就非常简单了,就是完完全全的拷贝出一个新的对象,不管源数据有几层,通通拷贝成新的对象,与源数据没有一点关系
三、实现方法
3.1、浅拷贝
<1>通过ES6的object.assign()
var a={name:"tom"};var b=Object.assign({},a);
<2>扩展运算符
var a={name:"tom"};var b={...a};
<3>for...in...
let copy=(obj)=>{let result={};for(var a in obj){result[a]=obj[a];}return result;}
3.2、深拷贝
<1>解构赋值
let a={age:10,address:{city:"shanghai"}};let b={...a,address:{...a.address}}
<2>递归
function deep(obj){let result=typeof obj.splice= = ='function'?[]:{};if(obj&&typeof obj = = ="object"){for(let key in obj){if(obj[key]&&typeof obj[key]= = ="object"){result[key]=deep(obj[key]);}else{result[key]=obj[key];}}return result;}return obj;}
全部评论
(2) 回帖