函数被调用时(出现()),JavaScript引擎立即创建其执行上下文并压入调用栈顶部。该过程自动完成,遵循LIFO规则,仅触发于调用而非定义,递归过深会导致栈溢出。

函数执行上下文在调用时被压入调用栈,是 JavaScript 引擎自动完成的底层机制,不需要手动操作。关键在于:**只要函数被调用(即出现 ()),引擎就立即为其创建新的执行上下文,并压入调用栈顶部**。
函数调用触发上下文创建
每次执行 foo()、bar(1, 2) 或 obj.method() 这类带括号的调用表达式时,引擎就会:
- 暂停当前正在执行的上下文(比如全局或上一个函数)
- 为被调用函数新建一个函数执行上下文(FEC)
- 填充该上下文的三个核心部分:变量环境(含参数、
var声明)、词法环境(含let/const、嵌套作用域链)、this值 - 将这个新上下文作为栈帧(stack frame)压入调用栈顶端
压栈过程严格遵循 LIFO 规则
调用栈是后进先出结构,压入顺序直接决定执行顺序和返回路径:
- 程序启动 → 全局执行上下文(GEC)最先入栈,位于栈底
-
a()被调用 →a的 FEC 入栈,成为当前活动上下文 -
a内部调用b()→b的 FEC 入栈,覆盖在a之上 -
b执行完 → 它的 FEC 立即弹出,控制权交还给a继续执行后续语句
注意:不是定义,而是调用才压栈
函数声明(function foo(){})或箭头函数赋值(const bar = () => {})本身不会触发压栈。只有真正执行到 foo() 或 bar() 这一刻,才会创建并压入对应上下文。
立即学习“Java免费学习笔记(深入)”;
例如:
function outer() {
console.log('outer start');
inner(); // ← 这里才压入 inner 的执行上下文
console.log('outer end');
}
function inner() {
console.log('inner');
}
outer(); // ← 这里先压入 outer 的执行上下文
压栈失败的情况:栈溢出
如果函数递归调用过深(比如没有终止条件的 fn() { fn(); }),调用栈持续增长超出引擎限制,就会抛出 RangeError: Maximum call stack size exceeded。这说明压栈行为真实存在,且有物理边界。


















