JS基础之作用域链

news/2024/7/5 4:46:21

JS基础之作用域链

  • 作用域链
    • 作用域链
    • 函数创建
    • 函数激活
    • 总结

作用域链

当JavaScript代码执行一段可执行的代码(execution code)时,会创建对应的执行上下文(execution context)。
对于每个执行上下文,都有三个重要的属性:

  • 变量对象(Varable object,VO)
  • 作用域链(Scope chain)
  • this
    本节来简单了解一下作用域链

作用域链

上节变量对象我们说到,当查找变量的时候,会先从当前上下文的变量对象中查找,如果没有找到,就会从父级(词法层面上的父级)执行上下文的变量对象中查找,一直找到全局上下文的变量对象,也就是全局对象,这样由多个执行上下文的变量对象构成的链表就叫做作用域链

函数创建

我们在词法作用域和动态作用域中讲到,函数的作用域在定义函数的时候就决定了。
这是因为函数有一个内部属性[[scope]],当函数创建的时候,就会保存所有父变量对象到其中,你可以理解[[scope]]就是所有父变量对象的层级连,但是注意[[scope]]并不代表完整的作用域链!
举个栗子:

function foo(){
	function bar(){
		...
	}
}

函数创建时,各自的[[scope]]为:

foo.[[scope]]=[
	globalConext.VO
];
bar.[[scope]] = [
	fooContext.AO,
	globalContext.VO
];

函数激活

当函数激活时,进入函数上下文,创建VO/AO后,就会将活动对象添加到作用链的前端。
这时候执行上下文的作用域链,我们命名为Scope:

Scope = [AO].concat([[Scope]]);

至此,作用域链创建完毕。

总结

结合着之前讲的变量对象和执行上下文栈,我们来总结一下函数执行上下文中作用域链和变量对象的创建过程:

var scope = "global scope";
function checkscope(){
	var scope2 = "local scope";
	return scope2;
}
checkscope();

执行过程如下:

  1. checkscope函数被创建,保存作用域链到内部属性[[scope]]
checkscope.[[scope]] = [
	globalContext.VO
];
  1. 执行checkscope函数,创建checkscope函数执行上下文,checkscope函数执行上下文被压入执行上下文栈
ECStask = [
	checkscopeContext.AO,
	globalContext.VO
];
  1. checkscope函数并不立刻执行,开始做准备工作,第一步:复制函数[[scope]]属性创建作用域链
checkscopeContext = {
	Scope:checkscope.[[scope]],
}
  1. 第二步:用arguments创建活动对象,随后初始化活动对象,加入形参、函数声明、变量声明
checkscopeContext = {
	AO:{
		arguments:{
			length:0
		},
		scope2:undefined
	},
	Scope:checkscope.[[scope]],
}
  1. 第三部:将活动对象压入checkscope作用域链顶端
checkscopeContext = {
	AO:{
		arguments:{
			length:0
		},
		scope2:undefined
	},
	Scope:[AO,[[Scope]]]
}

6.准备工作完成,开始执行函数,随着函数的执行,修改AO的属性值。

checkscopeContext = {
	AO: {
		arguments:{
			length:0
		},
		scope2:'local scope'
	},
	Scope:[AO,[[Scope]]]
}
  1. 查找到scope2的值,返回后函数执行完毕,函数上下文从执行上下文栈中弹出。
ECStask = [
	globalContext.VO
];

好啦!本节就讲到这里啦!
拓展一个小知识:AO和VO的关系
在这里插入图片描述


http://lihuaxi.xjx100.cn/news/1890222.html

相关文章

prim算法求最小生成树

Prim算法是一种求解最小生成树问题的贪心算法,其基本思想是从一个点开始,每次选择离已选取的点集合最近的一个点,添加到集合中,直到所有点都被选取。 以下是Prim算法的基本步骤: 初始化:选择一个起点作为…

I.MX RT1170双核学习(2):双核相互激活和启动流程

RT1170这个芯片带有双核:Cortex-M7和Corterx-M4,两个核都可以独立地运行,当然双核也可以同时运行。在上一篇文章中,介绍了一下在RT1170中消息模块MU的使用:双核通信之MU消息单元详解,因为这是双核之间用来通…

群晖(Synology)更换硬盘时间和精神双重折磨的教训

话说玩磁盘阵列的最后结果就是时间上负担不起,并且还被嫌弃。 在磁盘都到位后下一步就是要选择冗余类型了,对大部分人来说使用群晖自己提供的就好了,通常是 SHR。 什么是 SHR Synology Hybrid RAID(SHR)是 Synology…

Nacos配置Mysql数据库

目录 前言1. 配置2. 测试前言 关于Nacos的基本知识可看我之前的文章: Nacos基础版 从入门到精通云服务器 通过docker安装配置Nacos 图文操作以下Nacos的版本为1.1.3 1. 配置 对应的配置文件路径如下: 对应的application.properties为配置文件 需配置端口号 以及 mysql中的…

python自动化测试实战 —— CSDN的Web页面自动化测试

软件测试专栏 感兴趣可看:软件测试专栏 自动化测试学习部分源码 python自动化测试相关知识: 【如何学习Python自动化测试】—— 自动化测试环境搭建 【如何学习python自动化测试】—— 浏览器驱动的安装 以及 如何更…

Java二叉树的遍历

Java二叉树的遍历 大家好,我是免费搭建查券返利机器人赚佣金就用微赚淘客系统3.0的小编,也是冬天不穿秋裤,天冷也要风度的程序猿!今天,让我们一同探讨Java中二叉树的遍历,解锁这个数据结构的神秘面纱。 J…

【LeetCode每日一题】1904. 你完成的完整对局数

给你两个字符串 startTime 和 finishTime ,均符合 "HH:MM" 格式,分别表示你 进入 和 退出 游戏的确切时间,请计算在整个游戏会话期间,你完成的 完整对局的对局数 。 如果 finishTime 早于 startTime ,这表示…

成功解决 Plugin ‘org.springframework.boot:spring-boot-maven-plugin:‘ not found

Plugin ‘org.springframework.boot:spring-boot-maven-plugin:‘ not found的解决方案,亲测可用! 方法一:清理IDEA的缓存 File -> Invalidate Caches 方法二:添加版本号 先看自己当前的版本号 首先打开pom.xml文件进行查看C…