JavaScript中的预编译

JS运行三部曲

JS运行时一共分三步

 

(1)语法分析

    JS运行前会先把JS代码通篇扫描一遍,看有没有低级的语法错误,比如少了个分号,或者多了些不该有的字符什么的

(2)预编译

    本文的重点,后面会详细介绍,这里先放两句总结性结论

    函数声明  ---  整体提升 

            也就是说,函数声明后,系统会把整个函数放到当前script标签的开头处(这种说法并不严谨,仅仅是帮助理解)

    变量         ---  声明提升

            注意,是变量 --- 声明提升,也就是说var a  = 123; 系统会将var a;放到当前script标签的开头处(这种说法并不严谨,仅仅是帮助理解),但是a此时是undefined的,因为仅仅是声明提升,赋值操作并没有执行       

(3)解释执行

     解释型语言的特点,不通篇编译,而是解释一行执行一行

 

 

预编译

     预编译发生在函数执行前一刻

     准确来说,预编译一共有两种,一种是相对于调用函数而言的预编译,一种是在全局中的预编译

     先说函数中的预编译过程

     创建AO对象 (Activation Object)活动对象,又称上下文对象
     找形参和变量声明,将变量名和形参名作为AO属性名,值为undefined,
     将形参值和实参值统一,即把实参传递到形参处 (这一步是相对于调用函数而言,若直接在全局中可忽略)
     在函数体里找到函数声明,并将名字作为AO对象属性名,并把函数作为值,若之前已存在同名声明,则替换为函数
     

     为方便理解,先看一个demo

      

<script>
        function fn(a) {
            console.log(a);
 
            var a = 123;
 
            console.log(a);
 
            function a( ) { }
 
            console.log(a);
 
            var b = function ( ) { }
 
            console.log(b);
 
            function d( ) { }
        }
 
         fn(1);
</script>


        根据上面提到的预编译步骤,函数执行前

    创建AO对象
    找形参和变量声明,将变量名和形参名作为AO属性名,值为undefined
            AO {

                     a : undefined

                     b : undefined

            }

    将形参值和实参值统一,即把实参传递到形参处
            AO {

                     a : 1

                     b : undefined

            }

     在函数体里找到函数声明,并将名字作为AO对象属性名,并把函数作为值,若之前已存在同名声明,则替换为函数
            AO {

                     a : function a ( ){ }

                     b : undefined

                     d : function d ( ) { }

            }

     到此,预编译过程便结束了,接着开始正式执行函数体内容,

     console.log(a);   // function a ( ) { }

     a = 123;  // 注意之前预编译的步骤仅仅是声明了,并没有赋值

     此时AO对象的属性被修改

AO {
                     a : 123

                     b : undefined

                     d : function d ( ) { }

        }

    console.log(a);   // 123

   // function a ( ) { }  // 本行被跳过,因为在预编译环节已执行

   console.log(a);   // 123 

   b = function ( ) { }  //  之前预编译步骤已声明,这里仅仅是赋值

   此时AO对象的属性被修改

AO {
                     a : 123

                     b : function ( ) { }

                     d : function d ( ) { }

        }

  console.log(b);    // function ( ) { }

  // function d( ) { }   // 不会执行,预编译过程已经执行过

  此时,整个函数从预编译到执行环节便完整结束了

   

  接下来,我们再来说说全局中的预编译过程,其实和函数的预编译过程极其相似,只是少了一步

     创建GO对象 (Global Object)全局对象,又称window对象    (window object === global object)
     找变量声明,将变量名作为GO属性名,值为undefined,
     在函数体里找到函数声明,并将名字作为GO对象属性名,并把函数作为值,若之前已存在同名声明,则替换为函数
 这里就不再赘述了,原理都是一样的

 值得一提的,未经声明的变量是归全局变量所有的
 

<script>
    function test() {
        var a = b 10;
    }
  
    test();
    console.log(b);  // 10 
 
</script>


  var a = b =10;的过程:先把10赋给了未经声明的b,再把b的值赋给了a,那么此时b便提升为全局变量,如今在函数test外可以通过b或window.b直接访问这个全局变量

   

    还有最后一点,预编译过程无视if() {} 之类的判断语句,因为此时根本就还没执行函数,若if语句中有变量声明/函数声明是完全没问题的,是起作用的
--------------------- 
作者:Surrin1999 
来源:CSDN 
原文:https://blog.csdn.net/Surrin1999/article/details/83990710 
版权声明:本文为博主原创文章,转载请附上博文链接!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值