JavaScript运行原理以及作用域-作用域链
本文最后更新于 476 天前,其中的信息可能已经有所发展或是发生改变。

ES3版本

1.初始化全局对象

  • JavaScript引擎会在执行代码之前,会在堆内存中创建一个全局对象:Global Object(GO)
  • 该对象所有的作用域(scope)都可以访问,在浏览器中这个对象就是window
  • 里面会包含Date、Array、String、Number、setTimeout、setlnterval等等
  • 同时这里面还有一个window属性指向自己

2.创建执行上下文

  • JavaScript引擎内部有一个执行上下文栈(Execution Context Stack,简称ECS),它是用于执行代码的调用栈。
  • 全局的代码块为了执行会构建一个Global Execution Context(GEC)
  • GEC会被放入到ECS中执行
  • GEC被放入到ECS中里面包含两部分内容
    • 在代码执行前,会将全局定义的变量、函数等加入到GlobalObject中,但是并不会赋值; 而function定义的变量会创建对应的函数对象(只有function定义的会),并在GO里面保存对应的内存地址,这个过程也叫作用域提升
    • 在代码执行过程中,对变量赋值,或者执行其他的函数

3.关联VO对象

  • 每一个执行上下文会关联一个VO(Variable Object,变量对象),变量和函数声明会被添加到这个VO对象中
  • 当全局代码被执行的时候,VO就是GO对象了

4.开始执行代码

  • 在代码执行过程中,对变量赋值,或者执行其他的函数

5.遇到函数的调用时

执行前
  • 在执行的过程中执行到一个函数时,就会根据函数体创建一个函数执行上下文(Functional Execution Context,简称FEC),并且压入到ECS中
  • 同时因为每个执行上下文都会关联一个VO
  • 所以当进入一个函数执行上下文时,会创建一个AO对象(Activation Object)
  • 同时会将变量被初始化为 undefined,这是因为在函数的执行上下文被创建时,它们尚未获得具体的实参值
    • 接受的或者定义的都会被初始化
执行中
  • 这个AO对象会使用arguments作为初始化,并且初始值是传入的参数
    • 比如 foo(A,B){ console.log(arguments)} foo(10,20)
    • 首先在函数内部,可以通过 arguments 对象访问传入的所有参数10,20
    • 调用的过程中 AO 对象中的 a 和 b 被初始化为这个函数调用中传入的实参(即 10 和 20
  • 这个AO对象会作为执行上下文的VO来存放变量的初始化;
    • 当一个函数被调用时,会创建一个 AO 对象,这个对象被用来存储该函数内的所有变量和参数

6.执行结束

  • 当函数的代码执行完毕后,所有在函数内部定义的局部变量以及其他相关的执行信息(如 this 的值等)都随之被销毁
  • 销毁执行上下文并从调用栈中移除
  • 一旦上下文被销毁,与之相关的所有局部变量(包括AO 中存储的变量)将不再可访问,其内存也将被释放或重新分配
  • 如果没有对变量的引用,那么这个变量所占用的内存就会被标记为可以回收的区域。并可以由垃圾回收机制进行清理

作用域和作用域链

作用域
  • 作用域它定义了变量和其他标识符的可访问范围
  • 在ES5中全局是一个作用域,函数也会产生作用域
  • 在ES6中,代码块,let,const等也都会产生属于自己的作用域
作用域链
  • 作用域链用于解决变量和函数的查找问题,描述了在执行上下文中查找标识符的顺序和方式
  • 当进入到一个执行上下文时,执行上下文也会关联一个作用域链
  • 作用域链是一个对象列表,用于变量标识符的求值
  • 当进入一个执行上下文时,作用域链被创建,并且根据代码类型,添加一系列的对象
  • 通常作用域链在解析的时候就被确定了,作用域链与函数的定义位置有关,与函数的调用位置无关
具体查找流程

1.初始化全局对象并创建对应的 VO GO

2.代码开始执行并赋值

3.遇到函数调用,并创建对应的 VO AO

4.开始执行函数内的代码

5.当函数内的代码执行完成后

  1. 当foo函数执行完成会弹出执行上下文栈
  2. 把函数的返回值赋值给fn
  3. 同时因为inner对象里面有一个scope指向了AO1所以AO1的内存对象并不会被回收

6.在次遇到函数的调用,并创建对应的 VO AO

7.开始执行inner函数内的代码

8.开始查找变量

  1. 首先在自己的AO2里面找name,message,count
  2. 自己的AO2只找到name
  3. 往AO1里面查找message,count
  4. 找到所有变量并打印

9.函数执行完成后

  1. 当inner函数执行完成会弹出执行上下文栈
  2. inner AO2没有引用会被销毁

10.全局上下文执行完毕

  1. GO有一个window对象指向自身所以始终不会销毁

ES5之后

  • 大体逻辑与ES3版本基本一致具体如下
  • 执行上下文栈和执行上下文也是相同的
  • 在ES5之后,执行一个代码,通常会关联对应的词法环境
    • 一个词法环境是由环境记录(Environment Record)和一个外部词法环境(outerLexical Environment)组成
    • 环境记录也分为两种
      • 声明式环境记录
        • 如函数声明、变量声明和等
      • 对象式环境记录
        • 对象环境记录用于定义ECMAScript元素的效果,例如WithStatement,
  • 一个执行上下文里面又有两个环境
    • 词法环境 LexicalEnvironment
      • 用于处理let、const声明的标识符
      • 在同一个变量环境里面有限查找词法环境在查找变量环境
    • 变量环境 VariableEnvironment
      • 用于处理var和function声明的标识符
全局上下文执行的时候
遇到函数执行的时候

ES2023之后

  • 明确指出了LexicalEnvironment 和 VariableEnvironment 这两个组件“始终是环境记录(Environment Records)”。
  • 这意味着执行上下文中的这两个组件直接指向了环境记录,而不再通过其他结构(如词法环境)间接管理标识符的绑定
全局执行上下文
  • 全局执行上下文关联的是一个全局环境记录(Global Environment Record):
    • 全局环境记录实际上是一个包含了声明环境记录(Declarative Environment Record)
      • 里面存放let 和count定义的东西
    • 对象环境记录(Object Environment Record) 的组合体
      • 里面存放window里面的东西还要var function定义的变量函数
    • 全局环境记录的OuterEnv指向null
  • 变量查找过程
    • 在查找一个变量名N 时
    • 首先会在Declarative Environment Record (声明环境记录)中查找。
    • 若Declarative Environment Record 中存在该绑定,则直接返回 true,即查找成功。
    • 如果Declarative Environment Record(对象环境记录) 中没有找到该绑定,才会继续在Object Environment Record 中查找
函数执行上下文
  • 函数环境记录(Function Environment Record)是声明式环境记录(Declarative Environment Record)
    • 这意味着在函数的执行过程中,只会有一个环境记录,这个环境记录就是声明式环境记录。
  • 一个声明式环境记录(Declarative Environment Record)是如何区分函数中存放的var变量、let/const这些的呢?
    • CreateMutableBinding:用于创建 var 变量的可变绑定
    • CreateImmutableBinding:用于创建 let 和 const 变量的不可变绑定
      • 不可变绑定指的是一旦这个绑定(也就是这个名字到这个变量的关联)被创建后,它的绑定关系是不可改变的。
      • 具体来说,一旦通过CreateImmutableBinding 创建了绑定,你不能用同样的名字再次创建另一个绑定,且在初始化之前,不能访问或修 改这个绑定
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇