执行上下文
1.什么是执行上下文
小明写了一段js代码,运行时代码会被解析,相关函数被执行,解析和运行时存在的环境被称为执行上下文
2.执行上下文的类型
1.全局执行上下文
- 不在函数内部的代码都属全局执行上下文。
- 创建一个全局对象,其实就是我们的windown对象。
- 将this指向这个全局对象。
- 函数执行上下文:每次函数被调用的时候都会创建一个新的执行上下文
- 每个函数都有自己的执行上下文
- 一个程序中可以存在任意数量的函数执行上下文
- 每一个函数执行上下文被创建,他都会按照特定的顺序执行一系列步骤(先了解到这!)
- eval函数执行上下文:运行在eval函数中的代码也获得了自己的执行上下文
3.执行上下文的生命周期
总的来说:创建阶段————执行阶段————回收阶段
- 创建阶段:当函数被调用,但未执行内部的任何代码之前,会做一下几件事:
- 创建变量对象:首先会初始化函数的参数,提升函数声明和变量说明。
- 创建作用域链:在执行上下文创建阶段,作用域链是在变量对象之后创建的。
- 确定this指向
- 执行阶段:执行变量赋值,代码执行。
- 回收阶段:执行上下文出栈,等待回收。
作用域
1.什么是作用域
作用域就是一个独立的地盘,让变量不会外泄、暴露出去。也就是说作用域最大的用处就是隔离变量,不同作用域下同名变量不会有冲突。
ES6 之前 JavaScript 没有块级作用域,只有全局作用域和函数作用域。ES6的到来,为我们提供了‘块级作用域’,可通过新增命令let和const来体现。
全局作用域
- 所有window对象的属性拥有全局作用域
- 最外层函数 和在最外层函数外面定义的变量拥有全局作用域
- 所有未定义直接赋值的变量自动声明为拥有全局作用域
函数作用域:是指声明在函数内部的变量。
块级作用域:通过let和const声明。
注意:块语句(大括号“{}”中间的语句),如 if 和 switch 条件语句或 for 和 while 循环语句,不像函数,它们不会创建一个新的作用域。
实例1:
for (let index = 0; index < array.length; index++) {
var A = '123'
}
console.log(A) //123
实例2:
function fn (){
var A = '123'
}
fn()
console.log(A) //A is not defined
总结:ea5没有块级作用域so实例1除非用let或const才能隔离变量,实例2 因为在函数作用域里(没有变量提升)
2.作用域链
作用域链描述的是变量查找的规则;先从自己的作用域当中去查找,找到就使用,找不到会继续往上级去查找,一直找到全局为止;
中间如果首先找到就会使用,不再继续。如果没有找到继续往上找,直到找到全局都没有,报错(这个变量未定义)!这个查找变量的规则,过程被称作作用域链;
(作用域链也是一层链接这一层,每新建一层都会包含前面那一层的变量对象,最顶层的变量对象是最优先的)
总结
介绍完了 执行上下文、作用域、作用域链
但许多开发人员经常混淆这三者,误认为它们是相同的概念,但事实并非如此。
接下来让小明捋捋思路:
- 周六小明在西西弗书店写代码
- 函数定义好之后——> 作用域已经确定
- 此时点击run code
- 代码被运行 函数调用时——> 产生 函数执行上下文环境并创建作用域链并确定this指向
- 内部函数执行 ——> 变量赋值代码执行
- 执行完毕 ——> 函数执行上下文出栈 函数销毁 作用域链是在函数调用的时候才会有的,定义的时候不存在,作用域是函数定义的时候就已经确定好的;每个执行环境都会有自己独立的作用域链