前端一段关于函数执行上下文的分析
这里有段函数
function print(fn) {
const a = 200;
fn();
}
const a = 100;
function fn() {
console.log(a);
}
print(fn); // 100
对此执行顺序的分析如下
// 执行上下文栈
ECSTACKS = [
globalContext, // 全局执行上下文
];
// 初始化全局执行上下文
globalContext = {
// Variable Object
VO: {
arguments: {
length: 0,
},
a: 100,
},
scope: [VO],
};
执行print函数,向 执行上下文栈 顶部压入 print函数执行上下文
ECSTACKS = [
printContext, // print函数执行上下文
globalContext, // 全局执行上下文
];
// 复制父级作用域变量对象到 print函数的内置属性[[scope]]中
print.[[scope]] = [globalContext.VO];
// 初始化print函数的执行上下文,将内置属性[[scope]]作为上下文的作用域链,
// 生成活动对象,添加形参、函数声明、变量声明,
// 将活动对象压入作用域链的顶部
printContext = {
// Activation Object
AO: {
arguments: {
0: 1,
length: 1,
},
fn: `refer to function fn`,
a: 200,
},
scope: [AO, globalContext.VO],
};
// 执行fn函数,向执行上下文栈压入fn函数执行上下文
ECSTACKS = [
fnContext, // fn函数执行上下文
printContext, // print函数执行上下文
globalContext, // 全局执行上下文
];
// 复制父作用域(这里是全局作用域)的变量对象到内置属性[[scope]]中
fn.[[scope]] = [globalContext.VO];
// 初始化fn函数的执行上下文,将内置属性[[scope]]作为上下文的作用域链,
// 生成活动对象,添加形参、函数声明、变量声明,
// 将活动对象压入作用域链的顶部
fnContext = {
AO: {
arguments: {
length: 0,
},
},
scope: [AO, globalContext.VO],
};
// 执行函数fn,在fn函数执行上下文的活动对象AO中寻找a变量,未找到则通过作用域链,
// 寻找父级作用域的变量对象VO,找到a变量输出其值
// 100
执行完fn函数后,fn的函数执行上下文 从 上下文栈 中弹出 ECSTACKS.shift()
ECSTACKS = [
printContext, // print函数执行上下文
globalContext, // 全局执行上下文
];
fn执行完后print也就执行完毕,print函数执行上下文 从 上下文栈 中弹出 ECSTACKS.shift()
ECSTACKS = [
globalContext, // 全局执行上下文
];
也就说明了js采用的是
**静态作用域**,函数的作用域在定义的时候就确定了。

浙公网安备 33010602011771号