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

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

我们在学习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更加的高效。

相关文章
|
4天前
|
算法 程序员 索引
数据结构与算法学习七:栈、数组模拟栈、单链表模拟栈、栈应用实例 实现 综合计算器
栈的基本概念、应用场景以及如何使用数组和单链表模拟栈,并展示了如何利用栈和中缀表达式实现一个综合计算器。
11 1
数据结构与算法学习七:栈、数组模拟栈、单链表模拟栈、栈应用实例 实现 综合计算器
|
4天前
初步认识栈和队列
初步认识栈和队列
24 10
|
4天前
|
算法
数据结构与算法二:栈、前缀、中缀、后缀表达式、中缀表达式转换为后缀表达式
这篇文章讲解了栈的基本概念及其应用,并详细介绍了中缀表达式转换为后缀表达式的算法和实现步骤。
16 3
|
4天前
|
存储 算法
探索数据结构:分支的世界之二叉树与堆
探索数据结构:分支的世界之二叉树与堆
|
4天前
探索顺序结构:栈的实现方式
探索顺序结构:栈的实现方式
|
4天前
|
存储 C语言
栈和队列题目练习
栈和队列题目练习
8 0
|
11天前
|
存储 算法 搜索推荐
探索常见数据结构:数组、链表、栈、队列、树和图
探索常见数据结构:数组、链表、栈、队列、树和图
82 64
|
20天前
|
算法 安全 测试技术
golang 栈数据结构的实现和应用
本文详细介绍了“栈”这一数据结构的特点,并用Golang实现栈。栈是一种FILO(First In Last Out,即先进后出或后进先出)的数据结构。文章展示了如何用slice和链表来实现栈,并通过golang benchmark测试了二者的性能差异。此外,还提供了几个使用栈结构解决的实际算法问题示例,如有效的括号匹配等。
golang 栈数据结构的实现和应用
|
6天前
|
存储 安全 Java
【用Java学习数据结构系列】探索栈和队列的无尽秘密
【用Java学习数据结构系列】探索栈和队列的无尽秘密
15 2
|
11天前
|
Go
数据结构之 - 深入了解栈数据结构
数据结构之 - 深入了解栈数据结构
17 5