06 JS执行顺序:编译+执行

Posted by CodingWithAlice on April 10, 2021

06 JS执行顺序:编译+执行

image-20210410153255736

1、编译阶段

image-20210410153313919

编译阶段会生成两部分内容:

preview

  • 创建执行上下文 The Creation Phase
  • 可执行代码

    创建执行上下文(Execution context)

定义:执行上下文是JavaScript执行一段代码时的运行环境。比如调用一个函数,就会进入这个函数的执行上下文,确定该函数在执行期间用到的诸如this、变量、对象以及函数等。

对于每个执行上下文,都有三个重要属性:

1、this

2、建立 作用域链 (Scope chain) - 词法环境:当查找变量的时候,会先从当前上下文的变量对象中查找,如果没有找到,就会从父级(词法层面上的父级)执行上下文的变量对象中查找,一直找到全局上下文的变量对象,也就是全局对象。这样 由多个执行上下文的变量对象构成的链表 就叫做作用域链

3、生成 变量对象 (Variable object,VO) - 该对象中保存了变量提升的内容

详解如下:

  • 1、this 值的决定,即我们所熟知的 This 绑定

    • 全局执行上下文中 —> this 指向全局对象(浏览器中 - window

    • 函数执行上下文中 —> this 的值取决于该函数是如何被调用的

      —> 如果它被一个 引用对象 调用,那么 this 会被设置成那个对象,

      —> 否则 this 的值被设置为全局对象或者 undefined(在严格模式下)。

        let foo = {
            baz: function() {
                console.log(this);
            }
        }
        foo.baz();   // 'this' 引用 'foo', 因为 'baz' 被对象 'foo' 调用
              
        let bar = foo.baz;
        bar();       // 'this' 指向全局 window 对象,因为没有指定引用对象
      
  • 2、作用域链 - 创建词法环境组件 — let/const

    • 定义:

      词法环境由 环境记录器存储变量和函数声明的实际位置 – 作用域在函数定义的时候就决定) 和一个 外部词法环境的引用(可以访问其父级词法环境 - 作用域链) 组成。

    • 词法环境有两种类型:

      • 全局环境 没有外部环境引用的词法环境 -> null;环境记录器用于定义全局上下文中的变量和函数
      • 函数环境 外部环境引用可能是全局环境,也可能是任何包含此内部函数的外部函数;环境记录起用于存储变量、函数、参数
  • 3、创建 变量环境 组件 — var

    • 定义:同样是一个词法环境,其环境记录器持有 变量声明语句 在执行上下文中创建的绑定关系

    • 过程:

      preview

      —> 首先 建立arguments对象(函数参数) :检查当前上下文中的参数,建立该对象下的属性与 属性值

      —> 其次会处理函数声明 :在变量对象中以函数名建立一个属性,属性值为指向该函数所在内存地址的引用

      —> 再会 处理变量声明,变量对象中以变量名建立一个属性,属性值为 undefined,如果变量与函数同名,则 在这个阶段,以函数值为准,如下例子:

      image-20210706175225514

      image-20210707081437751

2、执行阶段

按照顺序一行一行地执行可执行代码

注意:

  • 一段代码如果定义了两个相同名字的函数,那么最终生效的是最后一个函数
    function showName() {
    console.log('我是个坑');
    }
    showName();
    function showName() {
    console.log('我还是个坑');
    }
    showName(); // 我还是个坑
    

    输出的结果是:‘我还是个坑’