代码分类(位置)
- 全局代码
- 函数(局部)代码
全局执行上下文
- 在执行全局代码前将window确定为全局执行上下文。
- 对全局数据进行预处理。
(1)var定义的全局变量==>undefined
,添加为window
的属性。
(2)function
声明的全局函数==>赋值(fun),添加为window
的方法。
(3)this==>赋值(window)
。 - 开始执行全局代码。
<script>
// 全局执行上下文
console.log(a1, window.a1)
a2()
console.log(this)
var a1 = 3
function a2() {
console.log('a2()')
}
console.log(a1)
</script>
函数执行上下文
- 在调用函数,准备执行函数体之前,创建对应的函数执行上下文对象
- 对局部数据进行预处理
(1)形参变量 ==> 赋值(实参) ==> 添加为执行上下文的属性。
(2)arguments
==> 赋值(实参列表),添加为执行上下文的属性。
(3)var定义的局部变量 ==>undefined
,添加为执行上下文的属性
(4)function
声明的函数 ==> 赋值(fun),添加为执行上下文的方法。
this ==> 赋值
(调用函数的对象) - 开始执行函数体代码。
<script>
// 函数执行上下文
function fn (a1) {
console.log(a1) // 2
console.log(a2) // undefined
a3() // a3()
console.log(this) // window
console.log(arguments) // 伪数组(2,3)
var a2 =3
function a3() {
console.log('a3()')
}
}
fn(2, 3)
</script>
执行上下文栈
- 在全局代码执行前,
JS引擎
就会创建一个栈来存储管理所有的执行上下文对象。 - 在全局执行上下文(
window
)确定后,将其添加到栈中(压栈)。 - 在函数执行上下文创建后,将其添加到栈中(压栈)。
- 在当前函数执行完后,将栈顶的对象移除(出栈)。
- 当所有的代码执行完后,栈中只剩下
window
。
<script type="text/javascript">
// 1.进入全局执行上下文
var a = 10
var bar = function (x) {
var b = 5
foo(x + b) // 3.进入foo执行上下文
}
var foo = function (y) {
var c = 5
console.log(a + c + y)
}
bar(10)
// 2.进入bar函数执行上下文
</ script>
先执行变量提升,再执行函数提升
举例如下:
<script>
function a() {}
var a
console.log(typeof a) //'function'
</script>
作用域与执行上下文
- 区别1
- 全局作用域之外,每个函数都会创建自己的作用域,作用域在函数定义时就已经确定了,而不是在函数调用时。
- 全局执行上下文环境是在全局作用域确定之后,js代码马上执行之前创建。
- 函数执行上下文是在调用函数时,函数体代码执行之前创建。
- 区别2
- 作用域是静态的,只要函数定义好了就一直存在,且不会再变化。
- 执行上下文是动态的,调用函数时创建,函数调用结束时就会自动释放。
- 联系
- 上下文环境(对象)是从属于所在的作用域
- 全局上下文环境 ==> 全局作用域
- 函数上下文环境 ==> 对应的函数使用域