第二十四篇 JavaScript内存机制之数据是如何存储的?

AI 概述
网上的资料基本是这样说的: 基本数据类型用栈存储,引用数据类型用堆存储。 看起来没有错误,但实际上是有问题的。可以考虑一下闭包的情况,如果变量存在栈中,那函数调用完栈顶空间销毁,闭包变量不就没了吗? 其实还是需要补充一句: 闭包变量是存在堆内存中的。 具体而言,以下数据类型存储在栈中: boolean null unde...

网上的资料基本是这样说的: 基本数据类型用栈存储,引用数据类型用堆存储。

看起来没有错误,但实际上是有问题的。可以考虑一下闭包的情况,如果变量存在栈中,那函数调用完栈顶空间销毁,闭包变量不就没了吗?

其实还是需要补充一句:

闭包变量是存在堆内存中的。

具体而言,以下数据类型存储在栈中:

  • boolean
  • null
  • undefined
  • number
  • string
  • symbol
  • bigint

而所有的对象数据类型存放在堆中。

值得注意的是,对于赋值操作,原始类型的数据直接完整地复制变量值,对象数据类型的数据则是复制引用地址。

因此会有下面的情况:

let obj = { a: 1 };
let newObj = obj;
newObj.a = 2;
console.log(obj.a);//变成了 2

之所以会这样,是因为 obj 和 newObj 是同一份堆空间的地址,改变 newObj,等于改变了共同的堆内存,这时候通过 obj 来获取这块内存的值当然会改变。

当然,你可能会问: 为什么不全部用栈来保存呢?

首先,对于系统栈来说,它的功能除了保存变量之外,还有创建并切换函数执行上下文的功能。举个例子:

function f(a) {
  console.log(a);
}

function func(a) {
  f(a);
}

func(1);

假设用 ESP 指针来保存当前的执行状态,在系统栈中会产生如下的过程:

  1. 调用 func, 将 func 函数的上下文压栈,ESP 指向栈顶。
  2. 执行 func,又调用 f 函数,将 f 函数的上下文压栈,ESP 指针上移。
  3. 执行完 f 函数,将 ESP 下移,f 函数对应的栈顶空间被回收。
  4. 执行完 func,ESP 下移,func 对应的空间被回收。

图示如下:

ESP 指针来保存当前的执行状态

因此你也看到了,如果采用栈来存储相对基本类型更加复杂的对象数据,那么切换上下文的开销将变得巨大!

不过堆内存虽然空间大,能存放大量的数据,但与此同时垃圾内存的回收会带来更大的开销,下一篇就来分析一下堆内存到底是如何进行垃圾回收并进行优化的。

更多相关文章推荐:

(建议收藏)原生 JS 知识系统整理

以上关于第二十四篇 JavaScript内存机制之数据是如何存储的?的文章就介绍到这了,更多相关内容请搜索码云笔记以前的文章或继续浏览下面的相关文章,希望大家以后多多支持码云笔记。

「点点赞赏,手留余香」

0

给作者打赏,鼓励TA抓紧创作!

微信微信 支付宝支付宝

还没有人赞赏,快来当第一个赞赏的人吧!

声明:本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若内容造成侵权/违法违规/事实不符,请将相关资料发送至 admin@mybj123.com 进行投诉反馈,一经查实,立即处理!
重要:如软件存在付费、会员、充值等,均属软件开发者或所属公司行为,与本站无关,网友需自行判断
码云笔记 » 第二十四篇 JavaScript内存机制之数据是如何存储的?

发表回复