内存的分配(示意)
启动程序,就需要分配内存给运行的程序。启动浏览器,就会分配一定内存供浏览器使用,浏览器在会分配相应的内存供诸如HTML+CSS
,JS
,'HTTP','其他插件、定时器`等模块使用,如下图。
会有一部分内存供JS
模块使用,JS
一般会将JS代码存储在代码区
,数据区
内,通过某种联系将代码和数据对应在一起,如下图。
内存图
示意图
内存图就是简化模拟示意JS
使用的内存中的数据区中的情况,简单的分为栈内存Stack
,堆内存Heap
,如下图。明显,左边是原始代码
,中间是栈内存
,右边是堆内存
。
使用
左边原始代码定义一个变量,在栈内存中就会用64位
存储一个值。如果原始代码中变量是非对象
,栈内存
中这个值就是直接值,堆内存
中没有数据。如果原始代码中变量是对象
,栈内存
中就会存储堆内存的地址(随机),堆内存
中会存储这个对象的所有内容。
看到上个图,原始代码区里最后一行O2=O
,将一个对象赋值给另一个变量时,实际上是将堆内存的地址
赋值给另一个变量,转换如下图,O2
在栈内存中的内容就变成了和O
一样的堆内存地址。
应用实例
第一个
- 原始代码中定义变量
a=1
,Stack中存储1 - 原始代码中定义变量
b=a
,Stack中存储b的值和a一样,为1 - 原始代码中赋值
b=2
,都是非对象,Stack中直接将b的值改为2,不影响a - 全程非对象,所以没有涉及堆内存Heap
第二个
- 原始代码中定义变量
a={name:'a'}
,是个对象,随机分配Heap地址(比如:31)并在Heap中存储这个对象,在Stack中存储这个Heap地址,比如ADDR 31
- 原始代码中定义变量
b=a
,是个存在的对象,将a的Stack值(ADDR 31)(Heap地址)赋给b的Stack值 - 原始代码中赋值
b=null
,赋给了b一个非对象,将b的Stack值改为null,不影响a - 全程操作Stack值,对象的Stack值为Heap地址
第三个
- 原始代码定义变量
a={n:1}
,随机分配Heap地址(比如:34)并在Heap中存储这个对象,在Stack中存储这个Heap地址,比如ADDR 34
- 原始代码中定义变量
b=a
,是个存在的对象,将a的Stack值(ADDR 34)(Heap地址)赋给b的Stack值 -
a.x=a={n:2}
,这句话阅读顺序从左往右
。首先,在Heap 34
中添加新属性x:a,现在a的值是ADDR 34
,所以新属性相当于x:ADDR 34。然后,把{n:2}
赋值给a,因为是个新对象,所以重新分配Heap地址(ADDR 54),并把a的Stack值变更为新的Heap地址(ADDR 51)。 -
alert(a.x)
,现在a的值实际是ADDR 54
,ADDR 54
里面是没有x这个属性的,所以返回undefined -
alert(b.x)
,b一直是ADDR 34
,其中x属性值为ADDR 54
,所以是个对象,返回[object Object] - 总之就是,原始代码里对对象的操作都在堆内存Heap中实现,对变量的操作都在栈内存Stack中实现。非对象的Stack值就是直接值,对象的Stack值是堆内存Heap的地址
第四个
- 原始代码中定义变量
a={name:'a'}
,Heap中存储对象,Stack中存储Heap地址(ADDR 101) - 原始代码
b=a
,把a的Stack值(Heap地址)赋给b的Stack值 - 原始代码
b={'name':'b'}
,赋给b一个新对象,Heap中存储新对象,b的Stack值变更为新的Heap地址(ADDR 301) - 所以,
a.name
没有变,还是a
第五个
- 原始代码中定义变量
a={name:'a'}
,Heap中存储对象,Stack中存储Heap地址(ADDR 51) - 原始代码
b=a
,把a的Stack值(Heap地址)赋给b的Stack值 - 原始代码设置
b.name=b
,就是ADDR 51
中的name值变更为b - 所以,
a.name
也就是ADDR 51
中的name值,等于b - 这里,a和b的Stack值都指向同一Heap地址,
ADDR 51
,所以无论对那个进行操作,都是对一个东西做操作,所以会互相影响
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。