JavaScript预编译(函数)

知识点预习

1、js文件的执行三部曲:语法分析、预编译、解释执行。

2、变量未经声明就使用,系统会报错。

3、var aa = "夫_子":变量的声明和赋值,aa为变量名,"夫_子"是变量值。var aa是变量的声明,aa = "夫_子"是变量赋值。

4、函数声明:function demo(){}。函数表达式:var demo=function(){}

 

一、语法分析

       js文件在执行的最开始,会将文件整体扫描一遍,检查是否含有最基本的语法错误,比如,含有中文符号、关键字单词拼写错误等等最基本的语法错误,此为语法分析。

 

二、预编译

       1、在说预编译之前,先看三个有意思的现象

   

        test();//夫_子
        function test(){
            console.log("夫_子"); 
        }
        test();//夫_子


        console.log(a);//undefined
        var a=123;
        console.log(a);//123

        
        b();//Uncaught TypeError: b is not a function
        var b=function(){
            console.log("夫_子");            
        }
        b();//夫_子


         console.log(c);//Uncaught ReferenceError: c is not defined

        看上面的例子,函数的执行,不管是放在函数定义之前,还是函数定义之后,都能执行出正确的结果,但是如果按照js的语言执行规则来解释,却又解释不通, 例如我们看到这里test的执行在函数的上面,如果按照代码的执行顺序,应该先执行test,再创造函数,那么显然就会报错,但此处却没有任何问题。

        第二个和第三个是变量的定义,变量a和b在定义之后执行,没有任何问题,但是在定义之前执行,却出现了两个不同的结果,a的执行结果是(undefined:未定义),没有报错,b的执行结果是(Uncaught ReferenceError: a is not defined:a没有定义),系统报错了。这一切都是为什么呢,为什么a不报错而b报错了呢,先别急,慢慢看,接下来才是重点。

     造成这一切的根本原因,就是代码执行前期的预编译,那什么是预编译呢?

     2、预编译

           简单来说,预编译主要有两点:一是变量、声明提升,二是函数整体提升,提升到语句执行逻辑的最前边。赋值和逻辑操作会被留在原地等待执行,即使赋值语句即等号后边是一个函数体。这么说,可能还是一知半解,甚至是完全看不懂,接下来实例讲解。

     3、实例讲解

      预编译四部曲:

              1、创建AO对象:执行期上下文(Activation Object)

              2、寻找形参和变量声明,并且当做属性放在AO对象里,并赋值为undefined

              3、将实参和形参统一

              4、寻找函数声明,值为函数体(此过程权重最高,如果和变量同名,会用函数体覆盖变量)

 function demo(a){
            console.log(a);//function a(){}  
            var a="夫_子";
            console.log(a);//夫_子
            function a(){}  
            console.log(a);//夫_子
            var b = function (){}//函数表达式
            console.log(b); //function (){}                    
        }
        demo(1)


/*预编译期间,各变量值得变化

    AO{ 

        a:undefined -->1 -->function a(){},

        b:undefined

  }




*/

1、创建AO对象:执行期上下文(Activation Object)

 

AO{     }

 

2、寻找形参和变量声明,并且当做属性放在AO对象里,并赋值为undefined

AO{ 

    a:undefined,

    b:undefined

  }

 

3、将实参和形参统一

AO{ 

    a:1,

    b:undefined

  }

 

4、在函数体里寻找函数声明,值赋予函数体(此过程权重最高,如果和变量同名,会用函数体覆盖变量)

AO{ 

    a:function a(){},

    b:undefined

  }

 

5、此函数在预编译结束的时候,AO里存储的对象就是如下,在执行函数的时候,再根据语句情况,修改相应的变量值

AO{ 

    a:function a(){},

    b:undefined

  }

上边的例子可以相对简单一些,下面来一个稍微复杂点的

        function test(a,b){
            console.log(a);//5
            c=0;
            var c;
            a=10;
            b=20;
            console.log(a);//10
            console.log(b);//20
            function b(){}
            console.log(b);//20
        }
        test(5);

/*预编译期间各变量值得变化

    AO{
        a:undefined -->5;
        b:undefined -->function b(){}
        c:undefined 
    }



*/

1、创建AO对象:执行期上下文(Activation Object)

 

AO{     }

 

2、寻找形参和变量声明,并且当做属性放在AO对象里,并赋值为undefined

AO{ 

    a:undefined,

    b:undefined

    c:undefined

  }

 

3、将实参和形参统一

AO{ 

    a:5,

    b:undefined

    c:undefined

  }

 

4、在函数体里寻找函数声明,值赋予函数体

AO{ 

    a:5,

    b:function b(){}

    c:undefined

  }

 

5、此函数在预编译结束的时候,AO里存储的对象就是如下,在执行函数的时候,再根据语句情况,修改相应的变量值

AO{ 

     a:5,

    b:function b(){}

    c:undefined

  }

 

函数的预编译过程,按照上面的四个步骤来进行,就不会出错。函数的优先级要比变量的优先级高,这里的优先级不是谁在前边,谁在后边,而是在预编译的过程中,如果变量名字和函数名一样,那么函数体会覆盖变量的undefined。

此文涉及的变量,都是局部变量,关于函数里未经声明就赋值的变量和全局变量怎么处理,会在下一篇全局下的预编译中详细讲解

三、解释执行

       js是一门解释性语言,解释型语言的程序没有运行前的编译过程,运行程序的时候才翻译,会有一个专门的解释器负责在每个语句执行的时候解释程序代码。解释一行执行一行。

函数在执行的前一刻,会创建一个独一无二的执行期上下文即AO,用来存储函数执行过程中需要用到的变量和函数声明,这个执行期上下文就是函数执行时的环境,在函数执行完毕之后,这个执行期上下文就会被销毁(闭包单独讲解),下一次调用函数的时候,又会重新创建一个新的执行期上下文。

函数在执行的时候,会根据函数的情况,修改AO中存储的变量值,例如:第一个例子中,函数执行到 var a="夫_子";语句时,会将AO中a的值修改为“夫_子”,有人可能会问,上边a的值是一个函数体function a(){},不是说,函数要比变量的优先级高么,那为什么a=“夫_子”还是会覆盖函数体。

在函数预编译的时候,函数的优先级要比变量的优先级高,但是在函数执行的过程中,变量的赋值语句会覆盖函数体。请看下边的例子,至于这些到底是为什么,这就是浏览器内核的解析规则了,


    function a() {}
    var a;
    console.log(typeof a);//fuction,此时a指向函数。

    var a;
    function a() {}
    console.log(typeof a);//function,此时a仍指向函数。


    function a() {}
    var a=5;
    console.log(typeof a);//number,此时a等于5。

    var a=5;
    function a() {}
    console.log(typeof a);//number,此时a等于5。

function test(a){
    console.log(a);//f a(){}
    var a=5;
    console.log(a);//5
    console.log(b);//f b(){}
    var b=function(){};
    console.log(b);//f (){}//和上一个b打印的函数,不是同一个函数
    function a(){}
    function b(){}
}
test(5)

此文是在看了腾讯课堂里的渡一教育的视屏课之后,结合自己的理解所写,如有错误,欢迎纠正!

 

 

 

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值