【JS】堆栈内存

106 阅读3分钟

当浏览器打开一个页面时,从计算机的虚拟内存中分配两块内存,每打开一个网页都会生成一个全新的ECS。

  • 栈内存 ECStack
  • 堆内存 Heap

栈内存

  • 存储原始值类型值
  • 供代码执行

堆内存

存储对象值 image.png

  1. 默认在堆内存开辟一个空间(16进制地址)->GO全局对象。存储浏览器为js提供的内置API (setTimeout)
  2. 在栈中创建全局执行上下文(EC(G))
  3. 全局变量对象VO(G):存储声明的变量
  4. 在全局上下文中会默认创建一个变量window,让其指向GO的地址,所以可以window.XX去访问浏览器内置的API

定义变量defined

例如 let value = 12

  1. 先创建值12
  • 原始值:直接存储在栈中
  • 对象:在堆中重新开辟一块空间,把地址赋值给变量
  1. 声明变量a
  2. 把12赋值给a(建立指针指向)
let a = {n:1}
a.x = a = {n:2}
// 正常从右到左计算,特殊情况:优先级高的先处理(成员访问)
//a.x = {n:2}  a = {n:2}

image.png

全局上下文中(只在全局上下文中有这个特点)

  • 基于var/function声明的变量,并没有放在VO(G)-script,直接存储在GO(global)中,作为window的成员
  • 基于let/const声明的变量存储在VO(G)中
  • c = 14 不加声明关键词放在GO(G)全局对象 image.png
  • 当把一个对象赋值给变量时,只是把地址赋值给变量。如果修改对象值,变量里的值也会跟着变化
let a = {n:1}  // a->ox001堆内存地址
let b = a  //b->ox001
a.n = 2
console.log(b) // b值地址指向不变
//{n: 2}

函数执行上下文

通过变量环境(var)与词法环境(let/const)存储声明的变量 image.png

函数底层处理机制

  • *在工作中尽量用函数表达式声明函数,防止函数提升以及在未声明前使用。
  • *函数是可执行对象,既有函数特点含有对象特点

创建函数

  1. 开辟一个堆内存空间(16进制地址)
  2. 创建函数时就声明了其作用域,在哪个上下文创建的,其作用域就是谁 [[scope]]:EC(G)
  3. 把函数体中的代码当作字符串存储
  4. 普通对象name函数名,length(形参个数)
  5. prototype 原型对象
  6. __proto__原型链
  7. 把空间地址赋值给变量(函数名)

image.png

执行函数

  • 创建一个全新的私有上下文EC(fn)->函数执行上下文
  • AO(私有变量对象)
  1. 代码执行之前
  • 初始化作用域链《函数私有上下文-函数作用域》
  • 初始化this
  • 初始化arguments
  • 形参赋值(私有变量-》Ao)
  • 变量提升
  1. 代码执行
  2. 关于上下文的回收释放 一般情况下,函数执行完,所形成的执行上下文会被释放。

image.png

作用域链

规划出变量的查找过程

  • 私有上下文中遇到一个变量,首先看是否时自己私有的,如果是,接下来对于对变量的操作都是私有的,和外界无关,{保护起来}
  • 如果不是私有,基于作用域链去上级上下文中找,知道找到EC(G)为止。