执行上下文与执行上下文栈
1.变量声明提升与函数声明提升
1)变量声明提升:使用var声明的变量,在定义语句之前就可以访问到,它的值为undefined。
2)函数声明提升:通过function()声明的函数,在执行之前就可以访问到,它的值为函数定义(对象)
—>两者执行顺序:先执行函数声明提升,再执行变量声明提升。
一道例题:
function fn(){
console.log(a)
var a=4
}
fn() //a输出 undefined
/*
* 上面函数体实质上等同于
* function fn(){
* var a
* console.log(a)
* a=4
* }
* 因为函数提升,所以在执行之前就可以访问到,而且由于变量声明提升,所以console.log(a)的值为undefined
*/
2.执行上下文
1)代码分类
*全局代码
*函数(局部)代码
2)全局执行上下文
①在执行全局代码之前将window确定为全局执行上下文
②对全局数据进行预处理:
*var定义的全局变量---->undefined,添加为window的属性。
*function声明的全局函数---->赋值(fun),添加为window的方法。
*this---->赋值(window)
③开始执行全局代码
3)函数执行上下文
①在调用函数,准备执行函数体之前,创建对应的函数执行上下文对象
②对局部数据进行预处理:
*形参变量---->赋值(实参)---->添加为执行上下文的属性
*arguements---->赋值(实参列表),添加为执行上下文的属性
*var定义的局部变量---->undefined,添加为执行上下文的属性
*function声明的函数---->赋值(fun),添加为执行上下文的属性
*this---->赋值(调用函数的对象)
③开始执行函数体代码
3.执行上下文栈
①.在全局代码执行之前,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>
实例流程如下:
⑥三个测试题
//测试题1
if (!(b in window)) {
var b=1
}
console.log(b) //undefined
//测试题2
function a(){}
var a
console.log(typeof a) //"function" 因为先执行变量提升,再执行函数提升
//测试题3
var c=1
function c(c){
console.log(c)
}
c(2) /*
* 该题会报错。该函数体等同于
* var c
* function c(c){
* console.log(c)
* }
* c=1
* c(2)
* c不是函数,无法调用
*/