资讯专栏INFORMATION COLUMN

浅析JS中的堆内存与栈内存

Faremax / 335人阅读

摘要:如,不是定义常量么为什么还能改这就是我们今天要说的重点中的堆内存与栈内存在引擎中对变量的存储主要有两种位置,堆内存和栈内存。而堆内存首先要在堆内存新分配存储区域,之后又要把指针存储到栈内存中,效率相对就要低一些了。

最近跟着组里的大佬面试碰到这么一个问题,

Q:说说var、let、const的区别
A:balabalabalabla...
Q:const定义的值能改么?
A:你逗我?不能吧

不知道各位看官怎么想?答案是部分能改,部分不能改。const定义的基本类型不能改变,但是定义的对象是可以通过修改对象属性等方法来改变的。如,

>>> const a = 1
>>> a
<<< 1
>>> a = 2
<<< VM1750:1 Uncaught TypeError: Assignment to constant variable.
    at :1:3
    (anonymous) @ VM1750:1
>>> const b = {}
>>> b
<<< {}
>>> b.name = 1
>>> b
<<< {name: 1}
>>> b = {}
<<< VM1785:1 Uncaught TypeError: Assignment to constant variable.
    at :1:4

const不是定义常量么?为什么还能改?这就是我们今天要说的重点~

js中的堆内存与栈内存

在js引擎中对变量的存储主要有两种位置,堆内存和栈内存

和java中对内存的处理类似,栈内存主要用于存储各种基本类型的变量,包括Boolean、Number、String、Undefined、Null,**以及对象变量的指针,这时候栈内存给人的感觉就像一个线性排列的空间,每个小单元大小基本相等。

而堆内存主要负责像对象Object这种变量类型的存储,如下图

栈内存中的变量一般都是已知大小或者有范围上限的,算作一种简单存储。而堆内存存储的对象类型数据对于大小这方面,一般都是未知的。个人认为,这也是为什么null作为一个object类型的变量却存储在栈内存中的原因。

因此当我们定义一个const对象的时候,我们说的常量其实是指针,就是const对象对应的堆内存指向是不变的,但是堆内存中的数据本身的大小或者属性是可变的。而对于const定义的基础变量而言,这个值就相当于const对象的指针,是不可变。

既然知道了const在内存中的存储,那么const、let定义的变量不能二次定义的流程也就比较容易猜出来了,每次使用const或者let去初始化一个变量的时候,会首先遍历当前的内存栈,看看有没有重名变量,有的话就返回错误。

说到这里,有一个十分很容易忽略的点,之前也是自己一直没有注意的就是,使用new关键字初始化的之后是不存储在栈内存中的。为什么呢?new大家都知道,根据构造函数生成新实例,这个时候生成的是对象,而不是基本类型。再看一个例子

var a = new String("123")
var b = String("123")
var c = "123"
console.log(a==b, a===b, b==c, b===c, a==c, a===c)    
>>> true false true true true false
console.log(typeof a)
>>> "object"

我们可以看到new一个String,出来的是对象,而直接字面量赋值和工厂模式出来的都是字符串。但是根据我们上面的分析大小相对固定可预期的即便是对象也可以存储在栈内存的,比如null,为啥这个不是呢?再继续看

var a = new String("123")
var b = new String("123")
console.log(a==b, a===b)
>>> false false

很明显,如果a,b是存储在栈内存中的话,两者应该是明显相等的,就像null === null是true一样,但结果两者并不相等,说明两者都是存储在堆内存中的,指针指向不一致。

说到这里,再去想一想我们常说的值类型和引用类型其实说的就是栈内存变量和堆内存变量,再想想值传递和引用传递、深拷贝和浅拷贝,都是围绕堆栈内存展开的,一个是处理值,一个是处理指针。

内存分配和垃圾回收

一般来说栈内存线性有序存储,容量小,系统分配效率高。而堆内存首先要在堆内存新分配存储区域,之后又要把指针存储到栈内存中,效率相对就要低一些了。
垃圾回收方面,栈内存变量基本上用完就回收了,而推内存中的变量因为存在很多不确定的引用,只有当所有调用的变量全部销毁之后才能回收。

继续往下思考的话,其中还有很多的东西需要去学习,今天先到这里,后续再来补充。

话说~NaN会不会也是存储在堆内存中的呢?大家想想吧,欢迎大家来一起讨论讨论~文中如有错误欢迎指出~

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/96984.html

相关文章

  • 与栈

    摘要:堆与栈栈由编译器自动分配存放函数的参数值局部变量的值等其操作方式类似于数据结构中的栈堆一般由程序员分配释放若程序员不释放程序结束时可能由回收这里是指操作系统区别和联系申请方式堆由程序员自己申请并指明大小在语言中的函数栈由系统自动分配声明在函 堆与栈 栈(stack): 由编译器自动分配, 存放函数的参数值, 局部变量的值等. 其操作方式类似于数据结构中的栈. 堆(heap): 一般由...

    April 评论0 收藏0
  • 【V8引擎】浅析Chrome V8引擎中的垃圾回收机制和内存泄露优化策略

    摘要:一前言的垃圾回收机制使用垃圾回收机制来自动管理内存。垃圾回收器只会针对新生代内存区老生代指针区以及老生代数据区进行垃圾回收。分别对新生代和老生代使用不同的垃圾回收算法来提升垃圾回收的效率。 V8 实现了准确式 GC,GC 算法采用了分代式垃圾回收机制。因此,V8 将内存(堆)分为新生代和老生代两部分。 一、前言 V8的垃圾回收机制:JavaScript使用垃圾回收机制来自动管理内存。垃...

    qingshanli1988 评论0 收藏0
  • js中深拷贝与浅拷贝(堆内存、栈内存的关系)

    摘要:而堆内存主要负责像对象这种变量类型的存储,如下图引用类型中复制浅拷贝的只是栈内存中的指针,指向同一个堆内存的对象如何实现深拷贝最简单的方法就是与方法 浅拷贝只会在引用类型中出现 基本数据类型有哪些,number,string,boolean,null,undefined,symbol以及未来ES10新增的BigInt(任意精度整数)七类。 引用数据类型(Object类)有常规名值对的无...

    AlienZHOU 评论0 收藏0
  • JS数据类型 与 内存堆栈

    摘要:所以相对于简单数据类型而言,他们占用内存比较小,如果放在堆中,查找会浪费很多时间,而把堆中的数据放入栈中也会影响栈的效率。六总结本文总结了数据类型及其声明赋值更新时在内存堆栈中的表现,可以更深入的理解这些数据类型。 JS数据类型 与 内存堆栈 一、前言 JS的数据类型已经是大家都很熟悉的东西了,但是大家是否对这些数据类型在内存中的分配了解,甚至在操作这些变量时,内存中是如何表现的,本文...

    nodejh 评论0 收藏0
  • js堆,栈与队列

    摘要:内存空间又被分为两种,栈内存与堆内存。今天就堆栈队列的内容就大概说到这里下一篇博客在继续说一下,有什么说的不对或者不足的地方,请大家批评指正 栈的定义 栈是计算机科学中的一种抽象数据类型,只允许在有序的线性数据集合的一端(称为堆栈顶端,英语:top)进行加入数据(英语:push)和移除数据(英语:pop)的运算。因而按照后进先出(LIFO, Last In First Out)的原理运...

    Kosmos 评论0 收藏0

发表评论

0条评论

Faremax

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<