基础巩固-执行上下文与执行上下文栈

172 阅读4分钟

执行上下文与执行上下文栈

变量提升与函数提升

1.变量声明提升(先提升)

  • 通过var定义(声明)的变量,在该定义语句之前就可以访问,但未赋值,返undefined!
  • 值:undefined

2.函数声明提升

  • 通过function声明的函数,在之前就可以直接调用,注意用函数表达式用的区别,表达式有var
  • 值:函数定义(对象)
var a = 3
function fn(){
    //var a 变量提升 未赋值
    console.log(a)//undefined
    var a = 4//赋值
    console.log(a)//4

}
fn()//undefined  4

/*****************/

console.log(b)// undefined 变量提升
fn2()//可调用 函数提升
fn3()//不能调用 没执行赋值操作不是函数,只是声明改变量  变量提升 var

var b = 3
function fn2() {//函数声明
    console.log("fn2()")
}
 	
var fn3 = function () {//函数表达式
    console.log("fn3()")
}

执行上下文

1.代码分类(位置)

  • 全局代码
  • 函数(局部)代码

2.全局执行上下文(准备工作)

  • 在执行全局代码前将window确定为全局执行上下文对象,只有一个

    • 全局数据进行预处理 * var定义的全局变量==>undefined,未赋值,添加为window的属性,当执行到赋值语句时才会赋值,变量提升 * function声明的全局函数==>赋值(fun),添加为window的方法,函数提升
    • this==>赋值(window)
  • 开始执行全局代码

c = 3 //window中没有,没用var定义
console.log(a1,window.a1)// undefined undefined
a2() //a2()
console.log(this) //window

var a1 = 3
function a2() {
    console.log("a2()")
}
console.log(a1) // 3

3.函数执行上下文

  • 调用函数,准备执行函数之前,创建对应的函数执行上下文对象(在栈空间中,非真实存在,封闭独有,注意与函数对象在堆空间区分)

  • 局部数据进行预处理

    • 形参变量==>赋值(实参)==>添加为函数执行上下文的属性
      • arguments(伪数组)==>赋值(实参列表),添加为函数执行上下文的属性
      • var定义的局部变量==>undefined,添加为函数执行上下文的属性,变量提升
      • function声明的函数==>赋值(fun),添加为函数执行上下文的方法,函数提升
      • this==>赋值(调用函数的对象)
  • 开始执行函数体代码,这才正式开始执行函数

【注】若是一个函数内嵌套两个函数,这两个函数是兄弟关系,则当其中一个函数调用执行时另一个并不执行,所有这里只会生成一个函数执行上下文对象!

function fn (a1) {
	console.log(a1) //2
	console.log(a2) // undefined
	a3()//a
	console.log(this) //window   window.fn(2,3)
	console.log(arguments) //伪数组(2,3)
	
	var a2 = 3
	function a3() {
	console.log("a")
	}
}

fn(2,3)

4.总结

n+1原则,n为调用函数次数,1为window,得出执行上下文个数

执行上下文栈

  1. 在全局代码执行前,JS引擎就会创建一个栈(后进先出,队列先进先出)来存储管理所有执行上下文对象
  2. 在全局执行上下文(window)确定后,将其添加到栈中,总在最底部(压栈)
  3. 在函数执行上下文创建后,将其压栈
  4. 在当函数执行完毕后,将栈顶的对象移除(出栈)
  5. 当所有代码执行完毕后,栈中只剩下window
var a = 10   //1.进入window全局执行上下文
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函数执行上下文
//函数每调用一次,生成一个函数执行上下文对象

面试题

console.log("ge:"+ i)  //ge:undefined                	//1.进入window全局上下文
var i = 1
foo(1);				 	//2.进入foo函数执行上下文
function foo(i) {
    if(i == 4){
        return;
    }
    console.log("fb:"+ i)
    foo(i+1)  //递归调用:在函数内部调用自己
    console.log("fe"+ i)
}
console.log("ge"+ i) //ge:1

/*依次输出什么
gb:undefined
fb:1
fb:2									栈 (嵌套调用)
fb:3								  X		foo 4	return
fe:3								fe:3	foo 3	fb:3
fe:2								fe:2	foo 2  	fb:2
fe:1								fe:1	foo 1 	fb:1
ge:1					向下 		   ge:1    Window  gb:undefined   向上
*/


//测试1  先执行变量提升,再执行函数提升
function a() {}
var a;//var a = 1   console.log(typeof a) number
console.log(typeof a)//"function"

//测试2 
if (!(b in window)){
    var b = 1
}
console.log(b)//undefined

//测试3
var c = 1
//var c
function c(c) {
    console.log(c)
}
// c = 1	 
c(2) //error c不是函数