V8 数据存储(上篇):栈和堆
栈和堆,用于存储数据的两种方式。在深入理解 V8 中的栈和堆之前,我们先看看语言本身。
JavaScript 是什么语言?
通常将语言分为静态语言和动态语言,像 C 语言这类在使用前需明确定义变量的数据类型,我们称之为静态语言,相反的,像 JavaScript 在运行过程中需要检查数据类型的,称之为动态语言。
同样的在 JavaScript 使用过程中,编译器经常偷偷的进行类型转换,比如在 If()
条件语句中,""
空字符串,会被转化为 false
,我们把这种现象称之为:隐式转换。 能进行隐式转换的语言,我们称之为弱类型语言,相反的不支持隐式转换的语言成为强类型语言。
所以,可以看出:JavaScript 是动态的、弱类型语言。
8 种数据类型
JavaScript 存在 8 种数据类型,其中 7 种为基础数据类型,1 种为引用类型,具体如下:
基础数据类型:
Boolean
| Number
| String
| Symbol
| BigInt
| Null
| undefined
引用类型:
Object
这里需要注意的是,typeof null === "object"
,这是历史遗留的 bug。区分不同类型的数据,是因为不同类型的数据存储的位置一样。
顺便提下,因为 Array
的 typeof
值也是 object
,所以日常我们判断数组有下面的方式:
栈和堆
一段代码经过编译,会产生一个执行上下文和可执行代码。在执行上下文中又分为变量环境和词法环境,变量环境用于存放当前上下文的变量,词法环境用于解决 JavaScript 中变量提升的问题,引入了块局作用域。以下面代码为例:
上面代码经过编译后,var a
将被放到变量环境,并赋初值undefined
;let b
,会被放到词法环境,注意此处并没有赋予初始值,倘若在未赋初始值便使用该变量,会形成一个暂时性死区,会报错。遇到function c
时,会将函数存储到堆中,同时将函数声明 c 放到变量环境,赋予函数在堆中的内存地址。
那这里为啥要将函数存在堆中,而不直接放在变量环境呢?
当代码开始执行后,会将当前代码编译后产生的执行上下文放入调用栈中,调用栈作为执行上下文切换的环境,当栈数据量越大,上下文数据销毁、切换需要消耗大量时间,会影响到整个程序的运行效率,因此栈空间一般都不大。也因为栈空间不大,当你疯狂递归执行某块代码,容易造成栈空间溢出。
堆空间用于存储引用类型,比如大对象,函数等等,会在分配存储空间、以及取数据存在一定的开销。
通过存储整个过程,我们可以得知,存在 3 中存储类型:栈、堆,以及代码空间。栈用于存储简单的基本数据类型,堆存储引用类型这些潜在的大数据对象。
涉及到堆和栈的数据存储,必然存在数据回收,也就是浏览器的垃圾回收机制。后面再讲!
版权声明: 本文为 InfoQ 作者【梁龙先森】的原创文章。
原文链接:【http://xie.infoq.cn/article/ed80a59f735ac524cddd82ca9】。文章转载请联系作者。
评论