本篇文章将主要介绍普通类型与对象在内存中储存方式的不同,也正因为这种不同,导致普通类型和对象在JS的使用中存在着一些结果的差异。以下文章纯属我的个人理解,如有错误之处,欢迎指出~
1.内存图的构造
如上图所示,在内存中,实际上分成了两个储存区块,一个为代码区,一个为数据区,代码区储存的是各种各样的变量名,而数据区则储存这些变量所引用的数据
2.内存存储普通类型数据和对象的方式
例如以下代码:
var a=1
var b={name:'xuan'}
机器在获得这段代码后,首先是对这段代码进行变量提升,即把声明变量的代码提到最前面来执行,之后在代码区读入一个a,数据区的stack区域读入一个1,在数据区,数值是以64位浮点数存储的,所以读入一个1,即读入一串64位的二进制码,在这里要说明的是,变量a和数据1是存在关联的。
之后代码区读入一个b,数据区的Heap区域内读入这个对象的“键值对”:{name:'xuan'},然后在stack区域记录这个对象的"键值对"的地址,这个地址与变量b也是存在关联的,在这里值得一提的是,对象在内存中之所以要以这样的存储方式存在,是因为这样可以方便之后对这个对象的一些操作的改变。
总的来说,就是普通类型的数据,是直接存储在stack内也就是栈内存中,而对象的存储,则是存储在堆内存内,并把堆内存的地址存储在栈内存的这种存储方式。
3.深拷贝和浅拷贝
拷贝在内存中的实际操作其实是把在栈内存内进行数据的覆盖,举个例子
var a=1
var b=2
a=b
以上代码中,首先声明了变量a和b的值,于是栈内存中便存储着两个数据1和2,分别对应着变量a和变量b,之后a=b,就是把b在栈内存中的值覆盖到a中,于是乎变量a所引用的数据从1变成了2,也就是说现在栈内存中存储着两个数据,分别为2和2,这两个数据也分别对应这变量a和变量b,这种拷贝方式称为深拷贝。
在缕清这个思路之后,我们可以开始尝试理解以下代码所代表的拷贝方式了。
var a={
name:'xuan',
age:'18'
}
var b=a
b.name='Jack'
console.log(a.name)
首先,声明了对象a的值,于是乎堆内存内便存储了这个对象的“键值对”,并把这个堆内存内数据的地址存储在了a所引用的栈内存内,也就是说现在堆内存内存储着对象a的数据,栈内存内存储着这个数据所存储的地址。
接着,b=a,根据拷贝的实际操作,b=a,就是把a栈内存内的内容对b进行覆盖,因此变量b的栈内存内现在存储着的也是对象a的地址,所以这时候进行操作b.name='Jack'
,实际上是对堆内存内存储的那个唯一的对象进行改变,因此再打出a.name时,输出的是改变之后的对象的内容。这种拷贝方式称为浅拷贝。
总而言之,普通类型进行的拷贝均为深拷贝,因为变量之间不会因为拷贝而互相影响,而对象的拷贝为浅拷贝,因为进行了浅拷贝后,对象之间会被互相影响。