持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第13天,点击查看活动详情
执行上下文
很多时候都说上下文调用,执行上下文,那么上下文到底是什么呢,我们具体分析一下。
从js引擎方面来看
- JS引擎并非逐行解析,而是一段段的分析和执行。这个分析,就是执行一段代码之前的准备工作,这个准备工作被称作为'执行上下文',执行上下文其实也在内存中开辟了一块空间
- JS可执行的代码段分为3种类型:1.全局 2.局部(函数) 3.eval()(不用)
从代码执行方面
为什么要有执行上下文
我们每运行一次代码,都会创建相对应的执行上下文,全局被称为全局执行上下文,局部被称为局部执行上下文。因为代码每次运行都会产生上下文的关联,所以需要有一个可以负责这些代码运行和管理的文件栈。
执行顺序
- 代码最开始运行,首先执行的是全局执行上下文,所以会在栈中压入一个全局执行上下文,等待页面运行结束,才会弹出
- 要执行一个函数,会创建一个局部执行上下文并压栈,当函数执行完成以后,就会把局部执行上下文从栈里弹出
从三个部分来具体剖析执行上下文
- this
- 变量对象
- 作用域链
this
有讲过,可跳转链接查看 JavaScript | 预解析以及this调用
变量对象
当执行上下文开启的时候,变量对象就会被激活,激活以后,作用域才能使用变量
简单介绍变量对象
- 变量对象和执行上下文相关,所以分为了 全局的变量对象(windown)和局部的变量对象
- 进入局部执行上下文,首先要生成一个变量对象,保存当前局部作用域中所有的变量(形参、声明的变量、声明的函数)
变量对象的生成
- 变量对象第一步先确定形参和实参,然后确定执行上下文中声明的函数,如果和形参同名,则完全覆盖
- 确定执行上下文中声明的变量,如果变量和形参或函数同名,则变量在赋值之前不会干扰同名形参和函数,以后在执行上下文中,如果使用变量 则直接去变量对象中查找即可
简单用代码表示就是这样
function fn(a) {
//下边声明的a不影响形参a的值
console.log(a); //1
var a = 2;
//变量a赋值之后,就覆盖之前的a
console.log(a); //2
}
fn(1);
作用域链
首先简单了解一下什么是作用域
作用域
什么是作用域
一句话概括:用来规定代码作用的范围及变量查询的范围
作用域的作用
隔离变量, 防止命名冲突
作用域什么时候产生及销毁
- 代码定义的时候产生
- 函数执行完销毁的是变量对象而不是作用域
- 作用域从代码定义的时候就一直在,除非没有当前代码
作用域链
- 函数创建的时候,会创建一个包含全局变量对象的作用域链(scope chain),作用域链是保证对执行环境有权访问的所有变量和函数 的有序访问
- 函数执行的时候,会创建自身的变量对象,把当前变量对象插入到 声明函数时候生成的作用域链顶端,完成整个作用域链
- 作用域链的顶端一定是当前执行环境的变量对象,作用域链末端一定是全局环境的变量对象window
作用域链的查找过程
查找变量的时候现在当前作用域的变量对象中查找,如果有就使用,如果没有会继续去上级作用域查找,直到找到全局作用域,如果还没有就报错,报错内容: xxx is not defined, 查找的过程就是沿着作用域链查找
结合作用域链面试题分析
var scope = "1";
function fn() {
var scope = "2";
function f() {
return scope;
}
return f;
}
console.log(fn()());
分析
输出是2,万里不变其一,就是作用域链其实就是在函数声明和变量定义的时候就确定了的,不管在哪调用,只需要看在哪声明就行,函数内部调用沿着作用域链网上找,不难就得出结果为2。
总结(执行上下文环境)
js代码在正式执行之前js引擎会先做一些准备工作
- 1.创建执行上下文环境
- 2.创建一个空的对象(执行上下文对象),该对象用于收集当前作用域的:变量,函数,函数的参数
- 3.确认this的指向
- 4.创建当前环境的作用域链
好了,以上就是本篇文章的分享,感谢阅读!