执行上下文与作用域

92 阅读2分钟

每一个上下文都有一个关联的变量对象(variable object),而这个上下文中定义的所有变量和函数都存在于这个对象上。

    使用let和const的顶级声明不会定义在全局上下文中,但在作用域链解析上效果是一样的。上下文在其所有代码都执行完毕后会被销毁,包括定义在它上面的所有变量和函数(全局上下文在应用程序退出前才会被销毁,比如关闭网页或退出浏览器。)

let a = 10 ;
let b = 10 ;
var c = 10

image.png

image.png
    每个函数调用都有自己的上下文。当代码执行流进入函数时,函数的上下文被推到一个上下文栈上。在函数执行完之后,上下文栈会弹出该函数上下文,将控制权返还给之前的执行上下文。

        function foo() {
            console.log('arguments:', arguments);
            let a = 10;
            bar();
        }
        function bar() {
            let b = 10;
            baz();
        }
        function baz() {
            let c = 10;
            console.log(`baz~~~~~~~~~~`);
        }
        foo()

image.png

image.png

执行上下文与作用域-流程图.jpg

    上下文中的代码在执行的时候,会创建变量对象的一个作用域链(scope chain)。这个作用域链决定了各级上下文中的代码在访问变量和函数时的顺序。代码正在执行的上下文的变量对象始终位于作用域链的最前端。如果上下文是函数,则其活动对象(activation object)用作变量对象。活动对象最初只有一个定义变量:arguments。作用域链中的下一个变量对象来自包含上下文,再下一个对象来自再下一个包含上下文。以此类推直至全局上下文;全局上下文的变量对象始终是作用域链的最后一个变量的对象。

image.png

    代码执行时的标识符解析是通过沿作用域链逐级搜索标识符名称完成的。搜索过程始终从作用域链的最前端开始,然后逐级往后,直到找到标识符。

    如下图,findFruit()函数使用了fruit变量,首先它会在自己的活动对象(变量对象)上查找是否由fruit变量,如果有就使用该fruit变量,否则向上一层上下文中的变量对象查找,以此类推,直到顶层上下文(全局上下文)

image.png

执行上下文与作用域1-流程图.jpg