函数执行三部曲

179 阅读3分钟

函数的执行顺序 1.语法分析(扫描一遍,看有没有语法错误之类的) 2.预编译 3.解释执行(解释一行,执行一行)

预编译和执行是分不开的,预编译就发生在函数执行的前一刻。预编译完成,马上逐行解释执行。下面讲预编译,里边含有解释执行的东西。 先铺垫几个知识点 函数声明整体提升 变量,声明提升 暗示全局变量,任何变量如果未经声明就赋值,此变量归全局所有。一切声明的全局变量,全是window的属性,比如b=3;意思就是window.b=3

变量,声明提升
var a=123相当于,var a;a=123;变量,
声明提升,把var a提升了,打印的话就是undefined

预编译四部曲: 1.创建AO对象 2.找形参和变量声明,将形参名和变量名作为AO属性名,增加到AO里面,并且赋值undefined 3.将实参赋值给形参 4.在函数体里找函数声明,值赋予函数体

第一步: 生成一个活动对象(Active Object),简称AO,又叫做执行期上下文 函数在运行前,会执行词法分析

第二步: 分析形参和变量声明,如var age;或var age=25; AO.age=undefine

第三步: 将实参赋值给形参,如果实参age=30,那么AO里面也跟着变化,这时候 AO.age=30

第四部: 分析函数的声明,如果有function age(){} 把函数赋给AO.age ,覆盖上一步分析的值

下面是一个例子,详细讲述函数执行三部曲,AO执行四部曲的
<script>
    function fn(a) {
      console.log(a);
      var a=123;  //相当于var a并且赋值为123
      console.log(a);//第三行
      function a() {    } //这个叫函数声明
      console.log(a);
      var b=function () {    }  //这个叫函数表达式,是b的声明赋值
      console.log(b);
      function d() {   }  //这个叫函数声明
    }
    fn(1);
    //首先进行语法扫描分析,没发现语法错误,就开始预编译,然后逐行解释执行
    //下面重点讲预编译四部曲
    /*1.创建AO对象
    2.找形参和变量声明,将形参名和变量名作为AO属性名,
       增加到AO里面,并且赋值undefined,这时候
    AO:{
        a:undefine,(形参是a,变量声明也有var a,那就只留一个)
        b: undefine,(变量声明var a和var b)
    }
    3.将实参赋值给形参,这时候
    AO:{
        a:undefine—>1,(实参a是1,这时候a=1)
        b: undefine
    }
    4.分析函数的声明,如果有同名的就覆盖,因为函数声明优先级最高,这时候
    AO:{
        a:undefine—>1—>function a() {    },(有同名的函数声明,就覆盖)
        b: undefine,(b不变)
        d:function d() {   } (增加了一个d,属于函数声明)
    }
    下面进入解释一行,执行一行的阶段,已经看过的就不再看了(比如var a)
    第一行:console.log(a);从AO里边找,打印出函数体
    第二行,var a已经不看了,只剩下赋值123了,这时候AO有变化
    AO:{
        a:undefine—>1—>function a() {  }—>123,
        b: undefine,
        d:function d() {   }
    }
    第三行:console.log(a)打印出123
    第四行:也不看了,之前已经提升过了
    第五行:console.log(a)也打印出123
    第六行:var b就不看了,只是把b赋值为函数体,这时候又修改AO
    AO:{
        a:undefine—>1—>function a() {  }—>123,
        b: undefine—>function () {    },
        d:function d() {   }
    }
    第七行:console.log(b);打印出函数体function () {    }
    第八行:不看了,之前提升过了。
    视频教程可以参考渡一教育递归,预编译(上)
    */
</script>

预编译不仅发生在函数内,也发生在全局