当我们写下 var a = 1 的时候,JavaScript引擎到底在做什么?首先从内存,内存条开始说。

Kingston

内存条如上图,上面有 8 个小黑块。内存条上的这些小黑块是用来存 0 和 1,比如存数字 2,那就把 2 变成二进制,也就是 10。0 是低电位,1 是高电位,然后存到内存里面,也就是内存是通过高低电位来存储数据的,所以内存须要一直通电。如果突然断电的话,所有内存中的 0 和 1 就都没了,数据都没了。如果要想数据都存起来,我们是把他们存到外存中,也就是硬盘中。比如我们把东西存到硬盘,关机后再开机,硬盘里面的东西还是在的,但是内存中的东西没了。每次开机的时候都要重新启动系统,系统会载入你的内存。

内存的特点就是,一旦断电,它里面的东西全部消失,所以要保持通电。内存的读写速度快。

外存的特点是,它里面的东西一直都在,但读写速度慢,目前最快的外存是 SSD 固态硬盘,能接近内存速度,现在很多人用固态硬盘来开机缩短开机时间。SSD 不易坏,但是 SSD 一旦坏了一点就整个坏了。另一种外存是机械硬盘,速度比 SSD 慢,容易坏,一般 10 年就会坏掉。不过机械硬盘坏了一点点是没有关系的,只要不去读它就可以了。另外价格上 SSD 比机械硬盘要贵。配置电脑的话,可以小体积的 SSD 加上大体积的机械硬盘配合,这样速度和空间就都有了。

我们开机就是把硬盘里面的操作系统读写到内存中。

如果我们有 2G 的内存,打开操作系统,操作系统占用了 512M 内存,操作系统开启后,我们打开浏览器,比如浏览器占了 1G(这里分配 1G 是因为 Chrome 浏览器很吃内存,所以购买电脑最低配 8G 内存。)浏览器把这个 1G 分配给每个页面,比如每个页面占 100M,而这个 100M 分配给 HTML + CSS 可能占 20M,一部分分配给 JavaScript 引擎 可能占 10M,让它去运行引擎,还有一部分分配网络模块 HTTP 可能占 20M,还有的分配给其他,比如说插件,定时器。JavaScript 引擎顶多能申请到 100M 内存。

所以当我们写下 var a = 1 的时候,JavaScript 引擎的 100M 内存会把 a 存在内存里的代码区,而 1 存在内存里面的数据区,然后 JavaScript 引擎会把代码区的 a 和数据区的 1 关联上,再进行 a 的其他运算逻辑的处理。到程序结束,a 会被销毁。

数据区分为两个区:栈 Stack 区内存、堆 Heap 区 内存。堆区内存存储的方式是个树的形式,像个堆一样,所以叫做堆内存。而栈区内存的组织结构像栈一样所以叫做栈内存。

stack-heap

然后我们看看下面这些代码是怎么在堆内存和栈内存中存储的

var a = 1
var b = 2
var o = {
name: 'panda',
age: 1
}
var c = true

第一步:JavaScript 引擎先分析语法,把所有 var 进行变量提升;

var a
var b
var o
var c
a = 1
b = 2
o = {
name: 'panda',
age: 1
}
c = true

a = 1,存到内存的栈中,JavaScript 里面的数字都是 64 位浮点数,小数点是浮动的所以叫浮点数。1 转为 64 位符点数格式是 0:2^1023:0

而 b = 2 ,2 的二进制是 10,64位符点数格式表示为 0:2^1024:0

如果 b = a 的话,就直接复制一份 a 到 b 的位置。

对象存储在堆中的,如果存在栈区中,对象的大小变化后,会需要除了修改对象之外,还要修改对象之后的栈中的其他值的位置,效率会很慢。所以最后对象存储在堆中,然后把堆的地址存在栈中。所以对象 o 的值会存在堆中,然后把它的地址比如 ADDR 100 存在栈中。

c 是 true,只需要 1 位,即 1

o2 = o,是直接把 o 的地址复制给 o2 的位置。

最后数据在内存中的存储大致是这样的:

总结:

JavaScript 语言的每一个值,都属于某一种数据类型。而 JavaScript 值的数据类型有 7 种。分别为基本类型(primitive type):字符串(string)、数值(number)、布尔值(boolean)、符号(symbol)、空值(null)、未定义的值(undefined),和复杂类型(complex type ):对象(object)。JavaScript 的基本数据类型存储在内存中的栈区中,复杂类型 object 存储在堆区中。