番外:透过JS代码看本质 - 04 从执行上下文对象入手看声明提前

本文详细介绍了JavaScript中的执行上下文(Execution Contexts)概念,包括全局和函数执行上下文的创建过程。重点讲解了变量对象(Variable Object)的创建,如声明提前、参数赋值和函数声明等步骤。同时,阐述了作用域链(Scope Chain)如何决定了变量和函数的访问规则,强调了JS的静态作用域特性以及内部函数对上层作用域的访问方式。
摘要由CSDN通过智能技术生成

从执行上下文对象入手看声明提前

资料

涉及到的关键词

  • 执行上下文(执行环境)
  • 活动对象、变量对象
  • arguments、声明提前
  • 作用域链

一、执行上下文(Execution Contexts)

(1) 为什么要有执行上下文

  • 每个函数都有对应的执行环境,它定义了变量或者函数有权访问的数据,决定他们各自的行为
  • 执行上下文(执行环境)是存在的对象,是规范中的存在和引擎上实现,JS无法访问,无法操作,只不过大家都这么叫,上一篇讲的是函数环境,是内存上的实现,要注意区分
  • 每个函数有自己的函数环境,函数环境都有对应的执行上下文(执行环境),函数环境是栈数据结构,那么执行上下文也应该是栈数据结构的,因为当恢复函数环境时,自然也要恢复执行上下文(执行环境)

(2) 什么时候开始建立执行上下文

每次执行函数前,会对函数进行预编译,这个时间段就在建立执行上下文。

执行上下文包含:

  • 变量对象(Variable Objecct),存储声明的变量和函数的具体位置
  • this value,确定this的值
  • 作用域链,确定能够访问的变量和函数

执行上下文也分:

  • 全局执行上下文
  • 函数执行上下文

(3) 建立执行上下文的过程

声明变量 var0
函数 A() {
    声明变量 var1
    函数 B()
    声明变量 var2
}

函数 B() {
    声明变量 var3
    函数 C()
    声明变量 var4
}

函数 C() {
    声明变量 var5
}

//执行函数 A
函数A()
  1. 代码一开始,先是全局执行上下文对象
globalExecutionContent = {
  VO: {
    arguments: undefined //默认是 undefined
  },
  Scope: [globalContent.VO],
  this: window
}
  1. 调用函数A,创建A函数的执行上下文对象
AExecutionContent = {
  VO: {
    arguments: undefined //默认是 undefined
  },
  Scope: [AExecutionContent.VO, globalExecutionContent.VO],
  this: window
}
  1. 其它函数的执行上下文对象也是如此,注意作用域链的最左端是当前执行上下文对象的变量对象,其后依次的是上层的执行上下文对象的变量对象

(4) 变量对象和活动对象

前面说过每个执行上下文都有一个对应的变量对象,但是注意执行上下文也是栈新式的结构,当前函数调用另外一个函数时,肯定也要保存当前的执行上下文,并创建新的上下文及其变量对象

此时,最上层的执行上下文和它的变量对象都是被 “激活的”,因为要执行当前环境代码必须访问执行上下文和它的变量对象

这样看其它的下层的执行上下文和它的变量对象都是 “休息状态”,在当前环境不需要访问它们

二、变量对象怎么创建的

这一小节涉及声明提前

进入函数并创建执行上下文对象时,对函数进行一扫描

  1. 扫描函数的所有形参,并将形参名称 和对应值组成的键值对作为变量对象VO的属性。如果没有传递对应的实参,将undefined作为对应值。如果形参名为arguments,将覆盖arguments(这里和上面执行环境对应)

  2. 扫描函数代码中所有的函数声明(注意是函数声明,函数表达式不算)
    将函数名和对应值(指向内存中该函数的引用指针)组成组成的键值对作为变量对象VO的属性
    如果变量对象VO已经存在同名的属性,则覆盖这个属性

  3. 扫描函数代码中所有的变量声明
    由变量名和对应值(此时为undefined) 组成,作为变量对象的属性
    如果变量名与已经声明的形参或函数相同,此时什么都不会发生,变量声明不会干扰已经存在的这个同名属性。

三、作用域和作用域链

(1) 作用域

  1. 变量(或者说标识)的作用域是程序源代码中定义这个作用域的区域
  2. 作用域是描述这个变量起作用的代码范围

(2) 作用域链

JS是静态作用域,这意味这一旦代码确定,作用域确定,并且不会改变

this不是作用域的一部分,可以从上一小节的执行上下文的作用域链可以看到 this和变量对象和作用域链是同级的

JS函数内部还能定义函数,内部函数还能访问上层函数的变量和函数(注意这个上层,是定义函数时的代码的上层环境或者说上层函数)

作用域链就像一个数组一样,它的最前端表示当前函数的作用域,往后就是上层函数的作用域,一直到全局环境,当需要访问变量或者函数时,查找方式就是按照这样的路径查询

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值