美文网首页
5.js引擎执行代码的过程

5.js引擎执行代码的过程

作者: 原来哥哥是万家灯火 | 来源:发表于2020-07-03 12:50 被阅读0次

    先来看看js引擎执行代码的过程:
    代码执行分为两个过程,先是分析阶段(可以理解为执行准备阶段),然后是真正执行阶段。分析阶段会对代码进行逐段的分析,在这个过程中完成参数声明、函数提升、变量提升、查明this等工作。执行阶段会对代码进行逐句执行,在这个过程总完成求值、赋值等。分析阶段是逐段,那么什么是段呢?一段全局代码、一个函数、一个eval(),即是一段。比如:

    var x = 1;
    function f() {}
    x = x+1;
    

    上面这段代码就分为两段,整体是一段,然后函数 f 又是一段。

    分析阶段的过程:

    • 创建一个对象,用于保存这段代码的环境信息,这个对象叫做执行期上下文对象
      let context = { [[scope]], VO, this };
      执行期上下文有三个属性,[[scope]]是作用域链,VO是变量对象,this就是当前this指向。

    • 将执行期上下文压入执行期上下文栈,(简称执行栈)。
      let stack = [];
      stack.push(context);

    • 依次解析此段代码的形式参数、声明函数、声明变量,然后保存在变量对象VO上
      解析形式参数(这一步只有函数上下文才有):
      在变量对象上的一个属性,属性名是形参名,值是 undefined

    假设代码段为函数: 
    function f(phoneNumber) {}
    
    context.VO = {
       arguments: {
           0: undefined
       },
       phoneNumber: undefined
    }
    

    声明函数(这就是函数提升):
    在变量对象上的一个属性,属性名是函数名,值是函数的引用。

    context.VO = {
       f: reference to function f(){}
    }
    

    如果变量对象已经存在相同名称的属性,则完全替换这个属性。如:

    function f (a) {
      function a() {};
      console.log(a);
    }
    打印结果是个函数。
    

    同理,两个同名函数,第一个会被第二个覆盖掉。

    function f (a) {}
    function f (a) {}
    
    context.VO = {
       f: reference to the 2nd function f(){}
    }
    

    试运行一段代码:

    function fn() {
      console.log(1)
    }
    
    fn();
    
    function fn() {
      console.log(2)
    }
    打印结果是2
    

    声明变量(这就是变量提升):
    在变量对象上的一个属性,属性名是变量名,值是 undefined。

    context.VO = {
       phoneNumber: undefined
    }
    

    如果变量名称跟已经声明的形式参数或函数相同,则变量声明不会干扰已经存在的这类属性。

    var c = 1;
    var c;
    console.log(c);
    打印结果是1
    
    var x = 1;
    function x() {};
    console.log(x);
    打印结果还是1
    
    • 查明this指向

    执行阶段:

    执行阶段会逐句执行代码,求值、完成对参数、变量的赋值等,或进入另一执行环境。如全局代码:

    var x = 1;
    function f() {
      var y = 2;
      console.log(x)
    }
    f();
    

    分析阶段完成后,其变量对象是这样的:

    globalContext.VO = {
        x: undefined,
        f: reference to function f(){}
    }
    

    执行x = 1;

    globalContext.VO = {
        x: 1,
        f: reference to function f(){}
    }
    

    执行f()
    创建 f 的执行期上下文,f 的上下文入栈...
    stack = [globalContext, fContext]...

    with语句、try...catch语句的catch,都会改变作用域链。with会把参数添加到作用域链的最前端,catch会把错误信息添加到作用域链的最前端。

    栈是一种数据结构,其特点是先入后出,后入先出。比如一个数组,let arr = [],当放入和移出数据,只使用push和pop,或者只使用unshift和shift时,它就具有先入后出、后入先出的特点,这就实现了一个栈。

    变量对象VO是一个抽象概念,是语言规范内规定的抽象概念。全局上下文的变量对象是全局对象,函数上下文变量对象是活动对象。globalContext.VO 是global object,fnContext.VO是fnContext.AO
    Variable object is an abstrat thing,which can be either of those:

    • global object (in global context)
    • activation object (in funtion context)

    相关文章

      网友评论

          本文标题:5.js引擎执行代码的过程

          本文链接:https://www.haomeiwen.com/subject/pohsqktx.html