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

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

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

相关文章
|
25天前
|
C语言
【数据结构】栈和队列(c语言实现)(附源码)
本文介绍了栈和队列两种数据结构。栈是一种只能在一端进行插入和删除操作的线性表,遵循“先进后出”原则;队列则在一端插入、另一端删除,遵循“先进先出”原则。文章详细讲解了栈和队列的结构定义、方法声明及实现,并提供了完整的代码示例。栈和队列在实际应用中非常广泛,如二叉树的层序遍历和快速排序的非递归实现等。
115 9
|
22天前
|
存储 算法 Java
散列表的数据结构以及对象在JVM堆中的存储过程
本文介绍了散列表的基本概念及其在JVM中的应用,详细讲解了散列表的结构、对象存储过程、Hashtable的扩容机制及与HashMap的区别。通过实例和图解,帮助读者理解散列表的工作原理和优化策略。
30 1
散列表的数据结构以及对象在JVM堆中的存储过程
|
16天前
|
存储 算法
非递归实现后序遍历时,如何避免栈溢出?
后序遍历的递归实现和非递归实现各有优缺点,在实际应用中需要根据具体的问题需求、二叉树的特点以及性能和空间的限制等因素来选择合适的实现方式。
22 1
|
3天前
|
存储 缓存 算法
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式,强调了合理选择数据结构的重要性,并通过案例分析展示了其在实际项目中的应用,旨在帮助读者提升编程能力。
21 5
|
18天前
|
存储 算法 Java
数据结构的栈
栈作为一种简单而高效的数据结构,在计算机科学和软件开发中有着广泛的应用。通过合理地使用栈,可以有效地解决许多与数据存储和操作相关的问题。
|
24天前
|
存储 搜索推荐 算法
【数据结构】树型结构详解 + 堆的实现(c语言)(附源码)
本文介绍了树和二叉树的基本概念及结构,重点讲解了堆这一重要的数据结构。堆是一种特殊的完全二叉树,常用于实现优先队列和高效的排序算法(如堆排序)。文章详细描述了堆的性质、存储方式及其实现方法,包括插入、删除和取堆顶数据等操作的具体实现。通过这些内容,读者可以全面了解堆的原理和应用。
61 16
|
21天前
|
存储 JavaScript 前端开发
执行上下文和执行栈
执行上下文是JavaScript运行代码时的环境,每个执行上下文都有自己的变量对象、作用域链和this值。执行栈用于管理函数调用,每当调用一个函数,就会在栈中添加一个新的执行上下文。
|
23天前
|
存储
系统调用处理程序在内核栈中保存了哪些上下文信息?
【10月更文挑战第29天】系统调用处理程序在内核栈中保存的这些上下文信息对于保证系统调用的正确执行和用户程序的正常恢复至关重要。通过准确地保存和恢复这些信息,操作系统能够实现用户模式和内核模式之间的无缝切换,为用户程序提供稳定、可靠的系统服务。
47 4
|
2月前
|
算法 程序员 索引
数据结构与算法学习七:栈、数组模拟栈、单链表模拟栈、栈应用实例 实现 综合计算器
栈的基本概念、应用场景以及如何使用数组和单链表模拟栈,并展示了如何利用栈和中缀表达式实现一个综合计算器。
33 1
数据结构与算法学习七:栈、数组模拟栈、单链表模拟栈、栈应用实例 实现 综合计算器
|
27天前
|
算法 安全 NoSQL
2024重生之回溯数据结构与算法系列学习之栈和队列精题汇总(10)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
数据结构王道第3章之IKUN和I原达人之数据结构与算法系列学习栈与队列精题详解、数据结构、C++、排序算法、java、动态规划你个小黑子;这都学不会;能不能不要给我家鸽鸽丢脸啊~除了会黑我家鸽鸽还会干嘛?!!!