执行上下文与作用域
引子:javaScript在执行语句前,经过一系列的准备,为代码执行创造一个‘教室’——执行上下文
执行上下文的文本环境(lexial Environment),类似教室的点名册
1 执行上下文的创建
1 执行栈(Execution Context Stack)
-
执行栈栈顶的执行上下文称为当前执行上下文
-
JS代码总是在当前上下文中运行
-
JS代码中需要用到的资源,到当前执行上下文查找 2 4种情况会创建新的执行上下文
-
进入全局代码
-
进入function函数体代码
-
进入eval函数参数指定的代码
-
进入module代码
2 执行上下文运作过程
Step 1: 创建全局执行上下文,并加入栈顶
Step 2: 分析:
- 找到所有的非函数中的var声明
- 找到所有的顶级函数声明
- 找到顶级let const class声明
找到块中声明的,函数名不与上述重复 ({}中)(3.4块作用域)
Step 3: 名字重复处理
- let const class 声明的名字之间不能重复
- let const class 和var function 的名字不能重复
- var和function名字重复的function声明名字优先
Step 4: 创建绑定
- 登记并初始化var为undefined
- 顶级函数声明:登记function名字,并初始化为新创建函数对象(函数对象'体内'会保存,函数创建时的执行上下文的文本环境)
- 块级中函数声明:登记名字,初始化为undefined
- 登记let const class ,但未初始化
Step 5: 执行语句
// 1. var和function 声明创建在全局对象中,而let const class 声明创建在全局scope中
// 2. 先到全局scope中找变量,查找不到再到全局对象中查找
console.log(Function);
console.log(window.Function);
// 打印结果一致
let Function = 'abc'
console.log(Function);//重新被定义在全局scope中
console.log(window.Function);
3 作用域
3.1 作用域是解析(查找)变量名的一个集合,就是当前运行上下文(也可以是当前上下文的词法环境)
- 全局作用域就是全局运行上下文
- 函数作用域就是函数运行上下文
3.2 函数调用时的执行上下文看'身世' ——函数在哪里创建,就保存哪里的运行上下文
函数的作用域是在函数创建的时候决定的而不是调用的时候决定
3.3 并非根据调用嵌套形成(运行上下文)作用域链,而是根据函数创建嵌套形成作用域链,也就是函数的书写位置形成作用域链,以此称为词法作用域
3.4 块级作用域
Step 1:创建新的记录环境,链接在原来记录之前
Step 2:分析:
- 所有的顶级函数声明
- 找到let const 声明
Step 3:
- function和let const 名字不重复
- let const 之间名字不重复
Step 4: 创建绑定
- 登记function名字,并初始化为新创建函数对象
- 登记let const 但未初始化
Step 5: 执行语句
块级作用域声明函数
// 找到块中声明,函数名与 let var function const 等重复,那么对块中函数不做处理,如果没重复,就在全局对象当中创建一个以函数名为名的变量,并把它初始化为undefined
// 执行到块级作用域时,会找let const 登记function ,并创建新的函数对象,记录块级作用域的文本环境,并到全局对象中查找是否有一个名字相同的变量,有的话把值赋值给这个变量,没有的话不做任何处理