JavaScript 中的执行上下文和执行栈

执行上下文概念

执行上下文就是评估和执行javascript代码的环境的抽象概念.每当javascript运行的时候,它都是在执行上下文中运行

执行上下文的类型

  1. 全局执行上下文: 这是默认的上下文,任何不在函数内部的代码都在全局上下文中.它会执行两件事: 创建一个全局window,并且设置this的值指向这个window. 一个程序中只有一个全局执行上下文
  2. 函数执行上下文: 每当一个函数被调用时, 都会为该函数创建一个新的上下文. 每个函数都有它自己的执行上下文, 不过都是在函数被调用时创建的. 函数上下文可以有多个, 每当一个新的执行上下文创建时, 它会按照定义的顺序执行一系列的步骤.

执行栈

是一种拥有后进先出数据结构的栈, 被用来储存代码运行时创建的所有执行上下文
为了模拟执行上下文栈的行为,让我们定义执行上下文栈是一个数组:

ECStack = [];

当javascript引擎第一次遇到你的脚本时.它会创建一个全局的执行上下文,并且压入当前执行栈,也就是数组ECStack中.

ECStack = [
    globalContext
];

每当引擎遇到一个函数调用.它会为该函数创建一个新的执行上下文并且压入当前执行栈的顶部.

引擎会执行那些执行上下文位于栈顶的函数。当该函数执行结束时,执行上下文从栈中弹出,控制流程到达当前栈中的下一个上下文
现在javascript遇到下面的这段代码:

function fun3() {
    console.log('fun3')
}
function fun2() {
    fun3();
}
function fun1() {
    fun2();
}
fun1();
// fun1()
ECStack.push( functionContext);
// fun1中调用了fun2,还要创建fun2的上下文
ECStack.push( functionContext);
// fun2调用了fun3 
ECStack.push( functionContext);
// fun3 执行完毕
ECStack.pop();
// fun2 执行完毕
ECStack.pop();
// fun1 执行完毕
ECStack.pop();

思考题:

// 比较下面两段代码,试述两段代码的不同之处
var scope = "global scope";
function checkscope(){
    var scope = "local scope";
    function f(){
        return scope;
    }
    return f();
}
checkscope(); // 

// B---------------------------
var scope = "global scope";
function checkscope(){
    var scope = "local scope";
    function f(){
        return scope;
    }
    return f;
}
checkscope()();

上面两端代码输出值是一样的, 都是local scope
但是执行上下文栈的变化不一样
第一段代码

ECStack.push( functionContext)
ECStack.push( functionContext)
ECStack.pop()
ECStack.pop()

模拟第二段代码

ECStack.push( functionContext)
ECStack.pop()
ECStack.push( functionContext)
ECStack.pop()

作用域

作用域是程序源代码中定义变量的区域
作用域规定了如果查找变量,也就是确定当前执行代码对变量的访问权限.
词法作用域: javascript采用的是词法作用域 也就是静态作用域, 函数的作用域是在定义的时候就决定了
动态作用域: 函数的作用域是在函数调用的时候才决定的

看下面例子

var value = 1;
function foo() {
    console.log(value);
}
function bar() {
    var value = 2;
    foo();
}
bar();

假如javascript采用静态作用域.
执行foo函数,先从foo函数内部查找是否有局部变量value.如果没有,就根据书写的位置,查找上面一层代码. 也就是value等于1. 所以结果会打印1

假设javascript采用动态作用域.
执行foo函数.依然是从foo函数内部查找是否有局部变量value.如果没有.就从调用函数的作用域. 也就是bar函数内部查找value变量,所以打印2

你可能感兴趣的:(javascript)