Skip to content

Latest commit

 

History

History
190 lines (129 loc) · 4.45 KB

js运行三部曲.md

File metadata and controls

190 lines (129 loc) · 4.45 KB

js运行三部曲

  • 语法分析

    js代码运行是一条一条的解释,而在解释前要进行的工作 就是语法分析,对全部语句进行一步检查,判断是否符合基本语法规则。

  • 预编译

    预编译前奏:

    1. 一切未经声明的变量都是全局变量,属于全局作用域window所有

      a = 1;
      

      不会报错,在全局范围内相当于

      var a = 1;
      

      a属于全局window,在全局的作用域内,但是不提倡这样。

      再来看一段

      function my(){
          var a = b = 3;
      }
      

      变量的赋值从右到左,相当于西安将3赋值给了b,然后a的值等于b。但是此时只有a被声明,b并未声明,所以b属于全局变量,作用域在window,而a则是局部变量,属于函数my;

    2. 变量 声明提升;函数声明整体提升。看例子

      var a = 1;
      console.log(a);
      

      此时打印出结果为 1 ;

      console.log(a);
      var a = 1;
      

      将a定义到输出下面,但是并不会报错。此时a的定义可分为倆步。

      var a; //声明 a;
      a = 1; //给a赋初值;
      

      当a被声明时,同时被提升到了作用域的顶端,所以相当于

      var a;
      console.log(a);
      a = 1;
      

      因此,打印出的是undefined;再来看

      function my(){
          var b = 1;
          console.log(b);
      }
      my();
      

      会打印出 1,没有问题

      my();
      function my(){
          var b = 1;
          console.log(b);
      }
      

      同样会打印出1.在js中,当函数被声明时他就被提到了作用域的顶端,而且是整个函数都被提升了,因此,my()函数执行无误;

      预编译四部曲

      1. 创建AO对象

      2. 找形参和变量声明,将变量和形参名作为AO属性名,值为undefined

      3. 将实参值和形参统一

      4. 在函数体里找函数声明。值赋予函数体

      在js代码执行前会创建一个GO对象,也就是全局作用域,而在每个函数执行前一刻会创建自己的AO对象,也称执行期上下文,看下面一段代码

      function my(a){
          console.log(a);
          var a = 123;
          console.log(a);
          function a(){}
          console.log(a);
          var b = function(){}
          console.log(b);
          function d(){};
      }
      my(1);
      

      在这个函数执行前,首先创建一个自己的AO对象(执行期上下文)

      AO{
          
      }
      

      第二步

      AO{
          a:undefined;
          b:undefined;
      }
      

      形参为a,变量声明为a和b,全部赋值undefined

      第三步

      AO{
          a:1;
          b:undefined;
      }
      

      a的实参为1.b无实参

      第四步

      AO{
          a:function a (){};
          b:undefined;
          d:function d (){}
      }
      

      找到函数声明并赋予,至于function b仅仅是一个函数表达式,并不是函数声明,至此,AO对象创建完毕,开始执行函数。这里有几个注意点

      • 声明的函数和变量在函数执行时忽略,因为都提升到了顶端

      • 对于 var a = 123; var b = function(){};这样的声明,虽然变量声明被提升了,但是前面讲过,这些语句可分为俩段。

        var a;
        a = 123;
        var b;
        b = function(){};
        

        因此,var a 与var b被提升忽略不看,但是俩条赋值语句仍在原地,当解释执行到此时会理所当然地将值赋予给变量。

        所以最后的打印结果应该是

        function a(){}
        123;
        123;
        function b(){};
        

        总的来说,变量声明提升和函数提升势必要覆盖其中一个,有一定的执行顺序,结果就是函数覆盖了变量。根据上面4点从后往前的访问顺序执行函数。

        GO对象

        GO即全局作用域,既然AO是在函数执行前一刻创建的,那么GO则是在window加载前一刻创建的全局执行期上下文,创建规则与AO相同。而对于函数

  • 解释执行

    当上述预编译执行完毕后,形成了GO和AO对象,js代码就可逐条执行,叫做解释执行,相关的作用域链在下一次介绍。