为什么基础数据类型存放在栈中,而引用数据类型存放在堆中?

简介: 为什么基础数据类型存放在栈中,而引用数据类型存放在堆中?

我们在学习JavaScript的数据类型的时候,学到的应该都是如下这样的知识点:


基本类型:string、number、boolean、undefined、null、symbol、bigint

引用类型:object


除此之外,要是学的更深入一些的话,也会学到这样一句话

这些数据类型在内存中存放方式如下:

栈:原始数据类型(Undefined、Null、Boolean、Number、String)

堆:引用数据类型(对象、数组和函数)

一般学到这里也就差不多到此为止了,我在之前复习的时候也是这样,知道我在面美团的时候,面试官这样问了我......

面试官:你知道js的数据类型有哪些吗?

我:基本类型有string、number、boolean、undefined、null、symbol、bigint。引用类型有object。

面试官:那你知道这些数据类型是以什么格式存放在内存空间的吗?

我:基本数据类型存放在栈中,引用数据类型存放在堆中。

面试官:还有么?

我:emmm,抱歉,我所了解的大致就这些了。

之后果不其然,我在面试过大约一周左右的时候,收到了感谢信......

那么今天,咱们就来深入学习一下,为什么基础数据类型存放在栈中,而引用数据类型存放在堆中?


栈的特点是:出口跟入口是同一个,遵循着先进后出、后进先出的原则数据只能顺序的入栈、顺序的出栈。 这也是我们学到的有关栈这一数据结构最重要的一个特性了,但是除此之外,栈还有着能直接存到底层寄存器,存取效率高、固定空间大小等特点。


堆的特点是无序的key-value键值对存储方式。堆的存取方式跟顺序没有关系,不会局限于出入口。


js的执行栈

执行栈又被称为执行上下文栈或调用栈。


程序执行进入一个执行环境时(比如整个script标签或进入一个函数内部),它的执行上下文就会被创建,执行上下文包含了函数的参数和局部变量,并被推入执行栈中(入栈);程序执行完成后,它的执行上下文就会被销毁,并从栈顶被推出(出栈),继续执行下一个执行上下文。

因为JS执行中最先进入全局环境,所以最开始处于栈底的是全局环境的执行上下文。而处于栈顶的是当前正在执行函数的执行上下文,当函数调用完成后,它就会从栈顶被推出。

我们所说的基本数据类型存放于栈中,说的也是执行栈的这个栈。

而js在执行的时候,就是将js代码从上到下遍历、然后不断的将事件及变量推入执行栈又不断从栈顶抛出的过程。


基本数据类型和引用数据类型的区别

基本类型

占用空间固定,保存在栈中

保存与复制的是值本身

可以使用typeof检测数据的类型


引用类型

占用空间不固定,保存在堆中

保存与复制的是指向对象的一个指针(浅拷贝)

使用instanceof检测数据类型

使用new()方法构造出的对象是引用型


为何基本数据类型存放在栈中

在js中,基本数据类型变量大小固定,并且操作简单容易,所以将其放入栈中存储。

基础数据类型的内存大小是固定的。就算是看似可以无限伸长的String字符串,也是有边界的,Number所能够表达的数值范围也限定于Number.MIN_VALUE到Number.MAX_VALUE之间,Boolean和Symbol类型就更小了。

而栈内存,恰好也是固定空间大小的。不仅是栈结构的每一项元素大小,而且整个栈结构的整体大小都是固定大小的,如果存放东西过多,就会栈溢出。

固定的内存空间位置意味着查找效率也会进一步提升。因为内存空间位置固定下来后,不必再一点点遍历查看这个对象是否结束,是否到了下一个对象,而是可以直接跳到下一个对象。

为何引用数据类型存放在堆中

引用数据类型的大小是不固定的,如数组可以无限扩充,对象可以自由添加属性。将他们放在堆中是为了不影响栈的效率。而是通过引用的方式查找到堆中的实际对象再进行操作。


最后

说到这里,大家应该也差不多明白为何基本数据类型存放在栈中,引用数据类型存放在堆中了。但是事实上,并非所有情况都如此。当我们使用了闭包的时候,JavaScript 引擎会沿着“当前执行上下文–>foo 函数闭包–> 全局执行上下文”的顺序来查找变量,而这一变量(不管是基本数据类型还是引用数据类型)也会被存到[[scope]]中,然后将其放到堆内存里面去。这也是可以理解的,就跟为什么引用数据要存放到堆中一样,是为了避免这些存储的数据在栈中影响到执行栈的执行,为了让js更加的高效。

相关文章
|
5月前
|
算法 C语言
通过指针引用数组
通过指针引用数组
47 1
|
5月前
|
存储 C语言
局部变量的储存区别
局部变量的储存区别
49 0
|
5月前
|
C语言
通过指针引用数组元素
通过指针引用数组元素
31 0
|
存储 程序员 编译器
指针存储数组 C
指针存储数组 C
72 0
|
5月前
|
存储 缓存 算法
对象和数组并不是都是在堆上分配内存的
对象和数组并不是都是在堆上分配内存的
42 0
|
存储
面试题:为什么不把基本数据类型放在堆中
面试题:为什么不把基本数据类型放在堆中
51 0
|
Java
Java引用与产生对象以及对应的堆空间、栈空间
Java引用与产生对象以及对应的堆空间、栈空间
70 0
|
C语言
【C 语言】内存四区原理 ( 栈内存与堆内存对比示例 | 函数返回的堆内存指针 | 函数返回的栈内存指针 )
【C 语言】内存四区原理 ( 栈内存与堆内存对比示例 | 函数返回的堆内存指针 | 函数返回的栈内存指针 )
138 0
【C 语言】内存四区原理 ( 栈内存与堆内存对比示例 | 函数返回的堆内存指针 | 函数返回的栈内存指针 )
|
存储 C语言
【C 语言】二级指针作为输入 ( 自定义二级指针内存 | 为 二级指针 分配内存 - 存放 一维指针 | 为每个 一级指针 分配内存 | 释放二维指针内存 )
【C 语言】二级指针作为输入 ( 自定义二级指针内存 | 为 二级指针 分配内存 - 存放 一维指针 | 为每个 一级指针 分配内存 | 释放二维指针内存 )
134 0
【C 语言】二级指针作为输入 ( 自定义二级指针内存 | 为 二级指针 分配内存 - 存放 一维指针 | 为每个 一级指针 分配内存 | 释放二维指针内存 )
|
存储 算法 安全
Java对象竟然会在栈上分配内存?(上)
Java对象竟然会在栈上分配内存?
425 0
Java对象竟然会在栈上分配内存?(上)