12-栈空间和堆空间

139 阅读3分钟

栈空间和堆空间

JS是什么类型的语言

在声明变量之前需要先定义变量类型,这种在使用之前就需要确认其变量数据类型的语言称为静态语言

这种类型的语言有C语言

JS是动态语言,指的是在运行过程中需要检查数据类型,也就是在声明变量之前不需要确认其数据类型

除了动态语言,JS还是一门弱类型的语言,弱类型语言指的是支持隐式类型转换的语言

JS的数据类型

现在我们知道,JS是弱类型、动态的语言:

  • 弱类型不需要告诉JS引擎某个变量是啥数据类型,JS引擎在运行代码的时候会自己计算出来
  • 动态:可以使用同一个变量保存不同类型的数据

JS的数据类型有8种:undefinednullnumberstringbooleanobjectsymbolbigInt

除了对象是引用数据类型,其他都是基本数据类型(原始类型)

内存空间

JS的内存空间分为三种:代码空间、栈空间、堆空间

代码空间主要是存储可执行代码的,这里先不做介绍

栈空间和堆空间

这里看一段代码:

 function foo(){
     var a = " 极客时间 "
     var b = a
     var c = {name:" 极客时间 "}
     var d = c
 }
 foo()

栈空间就是存储执行上下文的

由于变量ab都会被保存在执行上下文中,而执行上下文又被压入栈中,所以也可以认为变量ab存放在栈中

但是cd的处理就不一样了,变量cd不会将对象直接存放到变量环境中,而是分配到堆内存中分配后该对象会有一个在堆中的地址,然后再将这个地址写进cd的变量值中

也就是说,对象类型存放在堆空间中,栈空间中只是保留了对象的引用地址

这里分为栈和堆两个内存空间是因为:

栈是用来维护程序执行期间上下文的状态的,如果栈空间太大,所有数据都存放在栈空间中,则会影响上下文切换效率,从而影响整个程序的执行效率

所以一般栈空间不会太大,主要存放原始数据类型的一些数据,而引用数据类型一般都存放在堆中,因为堆内存比较大,但是这样分配内存和回收内存都会占用一定的时间

再谈闭包

我们再从内存角度了解一下闭包

 function foo() {
     var myName = " 极客时间 "
     let test1 = 1
     const test2 = 2
     var innerBar = { 
         setName:function(newName){
             myName = newName
         },
         getName:function(){
             console.log(test1)
             return myName
         }
     }
     return innerBar
 }
 var bar = foo()
 bar.setName(" 极客邦 ")
 bar.getName()
 console.log(bar.getName())

可能在分析执行上下文的时候会认为,myNametest1应该存在于foo的变量环境和词法环境中,foo函数执行完后,应该会把执行上下文清理掉,那为什么这里还保持着引用?

其实是因为JS引擎会对内部函数做一次快速的词法扫描,发现用用了外部函数的变量,则判断是一个闭包,会在堆空间中创建一个空间存放闭包对象

所以foo函数被销毁后,闭包还是存放在堆空间中不会被销毁,所以才可以保持引用关系

总的来说,产生闭包的核心有两步* *:第一步是需要扫描内部函数第二步是把内部函数引用的外部变量保持到堆中