执行上下文(Execution Context):函数执行前进行的准备工作(也称执行上下文环境)。
当执行代码进入一个环境时,就会为该环境创建一个执行上下文,它会做一些准备工作,如变量提升,确定作用域等。
一,执行上下文的类型
js中有三种执行上下文类型:
全局执行上下文:顶层上下文,任何不在函数内部的代码都在其中。上下文中的大哥大!它干了两件事:1.创建一个全局的window对象(浏览器环境下),2.设置this的值等于这个全局对象。(一个程序中只会有一个全局执行上下文)
函数执行上下文:函数被调用时,会创建新的上下文,可以有多个。
Eval函数执行上下文:aval函数专用,用的不多,没排面,不讨论。
执行栈
在js中,通过栈的存取方式来管理执行上下文,我们可称其为执行栈,或函数调用栈(Call Stack)。
栈遵循“先进先出,后进后出”的规则,也就是LIFO(Last In First Out)规则,可以用乒乓球盒子来类比理解。
特点:
1,先进先出,后进后出
2,出口在顶部,且仅有一个
当js引擎第一次遇到你的脚本时,它会创建一个全局的执行上下文并且压入当前执行栈。而每当引擎遇到一个函数调用,它会为该函数创建一个新的执行上下文并压入栈的顶部。
引擎会执行那些位于执行上下文顶栈顶的函数,当函数执行结束时,其执行上下文从栈中弹出,控制流程达到当前栈中的下一个上下文。
我们可以通过示例代码来理解:
function foo () {
function bar () {
return 'I am bar';
}
return bar();
}
foo();
二,执行上下文的生命周期
执行上下文的生命周期有两个阶段:
创建阶段(进入执行上下文,如:变量提升等)
执行阶段
创建阶段的操作:
1,创建变量对象
函数环境会初始化创建Arguments对象(并赋值),并传递长度length
匿名函数声明(并赋值)
变量声明,函数表达式声明(未赋值,即变量提升)
2,确定this指向(this由调用者确定)
3,确定作用域(词法环境确定,哪里声明,哪里确定)
执行阶段的操作
1,变量对象赋值
变量赋值
函数表达式赋值
2,调用函数
3,执行其他代码片段
值得注意的是,执行上下文可存在多个,因此在递归中可能因为没有终止条件而造成死循环,堆栈溢出错误。
// 递归调用自身
function foo() {
foo();
}
foo();
// 报错: Uncaught RangeError: Maximum call stack size exceeded
文末总结:
1,js是单线程
2,栈顶的执行上下文处于执行中时,其他的需要排队
3,处于底部的总是全局上下文,关闭页面时出栈
4,函数执行上下文可存在多个,但应避免递归时堆栈溢出
5,函数调用时就会创建新的上下文,即使调用自身,同样如此
参考文档:
https://mp.weixin.qq.com/s/lAvyjfBZvX0E50QiW3aW7w
https://juejin.im/post/5ba32171f265da0ab719a6d7(并未讨论其中的词法环境)
网友评论