执行上下文栈
一个思考题
1 | var scope = "global scope"; |
两段代码执行的结果均输出local scope
JavaScript 采用的是词法作用域,函数的作用域基于函数创建的位置
JavaScript 函数的执行用到了作用域链,这个作用域链是在函数定义的时候创建的。嵌套的函数 f() 定义在这个作用域链里,其中的变量 scope 一定是局部变量,不管何时何地执行函数 f(),这种绑定在执行 f() 时依然有效。
两端代码的压栈顺序
答案就是执行上下文栈的变化不一样。
第一段代码:
1 | ECStack.push(<checkscope> functionContext); |
第一代码在执行
checkscope()
时,内部的f()
也在函数内被执行。因此有连续两次的压栈操作。
让我们模拟第二段代码:
1 | ECStack.push(<checkscope> functionContext); |
在第二段代码中,
checkscope()
返回了函数f
,然后在返回的函数f
上执行了另一次()
,这导致了两次执行上下文的压栈和出栈。
作用域
代码中任何地方都能访问到的对象拥有全局作用域,一般来说以下几种情形拥有全局作用域:
- 最==外层函数==和==在最外层函数外面定义的变量==拥有全局作用域
1 | var outVariable = "我是最外层变量"; //最外层变量 |
- 所有末定义直接赋值的变量自动声明为拥有全局作用域
1 | function outFun2() { |
- 所有 window 对象的属性拥有全局作用域
执行上下文栈的流程
压入全局上下文
当执行一个到函数时,会创建一个函数执行上下文(Function Execution Context),并将其压入执行上下文栈。这个函数执行上下文包括了函数的参数,以及在函数内部声明的变量和函数。
在 JavaScript 中,存在全局执行上下文(Global Execution Context)和函数执行上下文(Function Execution Context)。全局执行上下文在浏览器开始读取脚本时创建,只有一个。而函数执行上下文每当函数被调用时都会创建。
每个执行上下文都有一个关联的变量对象(Variable Object),它包含了在上下文中定义的所有变量和函数。在函数执行上下文中,活动对象(Activation Object)扮演了变量对象的角色,它在函数执行上下文被推入执行上下文栈时创建,包含了函数的参数,以及在函数内部声明的所有变量和函数。
执行函数执行上下文
执行上下文的代码会分成两个阶段进行处理:分析和执行,我们也可以叫做:
进入执行上下文