开发中,声明变量是每个前端都经常做的一件事,那么你声明的变量都是怎么存放的呢?
开发中的变量按数据类型分为
基本数据类型(Undefined、Null、Number、String、Boolean和Symbol)
引用数据类型(Object)
浏览器内存空间中有栈和堆,其中
栈存放基本数据类型以及引用数据类型的内存地址
堆存放引用数据类型
下面我们用图更加形象的解释一下栈和堆:
可以看到,当查找引用数据类型的时候,先在栈中找到它的内存地址,然后通过内存地址找到堆中的Object(可能这就是叫做引用数据类型的原因吧)
计算机对栈的读取要比堆快,而且栈中每个变量占有固定大小的空间,而Object的大小是变化的(可以对其进行增删改查操作),所以Object放在堆中,但是栈中存放有它对应的内存地址,通过这种方式实现引入数据类型的读取和操作。
可能代码+图会更加好理解:
let a = 1,b = 'str',c = {name:'c'},d = false;复制代码
接下来我们看几个例子:
let a = 1; let b = a; a = 2; a // 2 b // 1复制代码
let a = 1,在内存中开辟a的内存1
let b=a,在内存中开辟b的内存1
a = 2,将a内存中的值修改为2
let obj1 = {name:'obj1'}; let obj2 = obj1; obj1.name = 'obj2'; obj1 // {name:'obj2'} obj2 // {name:'obj2'}复制代码
let obj1 = {name:'obj1'},在堆中保存对象 {name:'obj1'},并将变量obj1指向该对象的内存地址
let obj2 = obj1,在栈中创建obj2的空间,并将其指向{name:'obj1'}的内存地址
obj1.name = 'obj2',通过obj1对{name:'obj1'}的引用,修改其name为obj2,所以该对象变为{name:'obj2'}
总结:(源自高程3)
如果从一个变量向另一个变量复制基本类型的值,会在变量对象上创建一个新值,然后把该值复制 到为新变量分配的位置当从一个变量向另一个变量复制引用类型的值时,同样也会将存储在变量对象中的值复制一份放到 为新变量分配的空间中。不同的是,这个值的副本实际上是一个指针,而这个指针指向存储在堆中的一 个对象。复制操作结束后,两个变量实际上将引用同一个对象。因此,改变其中一个变量,就会影响另 一个变量
既然说到内存,我们就再谈一下浏览器内存空间的管理,如上所述
当声明一个变量的时候,如果为基本数据类型,浏览器会为其在栈中分配内存空间,如果为引用数据类型,浏览器会为该变量在栈中分配内存空间,同时将其声明的Object存放在堆中,并将该变量指向Object的内存地址
接下来是该变量的使用过程(读,写)
如果该变量不再被使用,则将其释放,浏览器的垃圾回
而JavaScript 中最常用的垃圾收集方式是标记清除
当变量进入环境的时候(如:变量被声明),将其标记为‘进入环境’,而当该变量不再需要的时候,则将其标记为‘离开环境’。每隔一段时间,浏览器的垃圾收集器就会运行一次,将标记为‘离开环境’的变量回收,并释放其内存。
注:以上为了方便理解对垃圾回收机制做了简化。
如果有错误或者不严谨的地方,请给予指正,十分感谢!