zoukankan      html  css  js  c++  java
  • 从var func=function 和 function func()区别谈Javascript的预解析机制

    var func=function 和 function func()在意义上没有任何不同,但其解释优先级不同
    后者会先于同一语句级的其他语句。

    即:

    {
     var k = xx();
     function xx(){return 5;}
    }


    不会出错,

    {
     var k = xx();
     var xx = function(){return 5;}
    }

    则会出错。

    为什么会这样呢?这就要引出javascript中的预解析机制来解释了。

    JavaScript解析过程分为两个阶段,一个是编译阶段,另外一个就是执行阶段。

      * 编译阶段

             编译阶段就是我们常说的JavaScript预解析(预处理)阶段,在这个阶段JavaScript解释器将完成把JavaScript脚本代码转换到字节码。

      * 执行阶段

        在编译阶段JavaScript解释器借助执行环境把字节码生成机械码,并顺序执行。

    编译阶段(预解析阶段)做什么操作?

      * var , function声明的变量提升

        首先,创建一个当前执行环境下的活动对象,然后将用 var 声明的变量设置为活动对象的属性(也就是将其添加到活动对象当中)并将其赋值为undefined,然后将function 定义的函数 也添加到活动对象当中。

    复制代码
    1 if( false ){
    2     var aa = 20;
    3     var bb = 30;
    4 }
    5 
    6 function AA(){};
    7 function BB(){};
    8 
    9 //var定义的aa,bb以及function定义的AA(),BB()都会被变量提升到window对象下面
    复制代码

        * 函数声明与函数表达式在预解析的区别

        首先,我们知道解析器会对function定义的函数(也就是函数声明)在代码开始执行之前对其实行函数声明提升(function declaration hoisting),所以在函数声明之前调用该函数是不会在执行期间报错,但是函数表达式不同,函数表达式用 var 声明,也就是说解析器会对其变量提升,并对其赋值为undefined,然后在执行期间,等到执行到该var 变量的时候再将其变量指向一个function函数,所以在函数表达式之前执行该函数是会报错的。

    复制代码
    1 AA();
    2 function AA(){};
    3 
    4 BB();
    5 var BB = function(){};
    6 
    7 //AA();不会报错,因为是以function的变量提升,BB()会报错,因为是以var的变量提升,到其相当于 BB(); var BB = undefined; BB = function(){};
    复制代码

      * function 覆盖

        若定义了两个同名的函数,则在预解析期间后面一个会覆盖签名一个

    复制代码
    1 AA();   // 输出 I am AA_2;
    2 function AA(){
    3    console.log('I am AA_1');
    4 };
    5 
    6 AA();  // 输出 I am AA_2;
    7 function AA(){
    8   console.log('I am AA_2');
    9 }
    复制代码

      * 预解析把变量或函数解析到其运行时的环境中

        解析器将变量提升并不是将所有的变量都提升到window对象下面,其提升的原则是提升到变量运行的环境中去。

    复制代码
     1 aa = "I am aa";
     2 (function(){
     3     console.log(aa);  // 输出 aa 是 undefined
     4     var aa = "I am aa in a function";
     5     console.log(aa);  //输出 aa 是 I am aa in a function
     6 })();
     7 
     8 // 这里 aa 被变量提升,但是aa 没有被变量提升到 window下面,而是被提升到其运行的环境 (function(){ })() 中去,也就是等同于
     9 
    10 // aa =  "I am aa";
    11 //(function(){
    12 //    var aa;  
    13 //    console.log(aa);  // 输出 aa 是 undefined
    14 //    aa = "I am aa in a function";
    15 //    console.log(aa);  //输出 aa 是 I am aa in a function
    16 //})();
    17 
    18 
    19 
    20 // 下面代码等同于上面,目的是为了若看不懂上面,则可看下面。
    21 aa = "I am aa";
    22 function AA(){
    23     console.log(aa);
    24     var aa = "I am aa in a function";
    25     console.log(aa);
    26 }
    27 AA();
    复制代码

      * JavaScript“预解析”分段进行

        所谓分段进行是按照<script>标签来分块进行预解析

    复制代码
     1 <script>
     2 AA();  // 输出 AA2;
     3 function AA(){
     4    console.log('AA1');
     5 }
     6 
     7 function AA(){
     8    console.log('AA2');
     9 }
    10 </script>
    11 
    12 
    13 <script>
    14 function AA(){
    15    console.log('AA3');
    16 }
    17 </script>
    18 
    19 //上面例子说明function函数声明是分块的,然而至于var变量的提升经过反复验证是不分块的( 此处如有不同意见请指教 )。
    复制代码

      * var 变量提升以及 function 函数声明提升

        该点是对函数声明以及函数表达式进一步的说明,其实前面函数声明和函数表达式在预解析的不同表现,其主要的原因就是 var 和 function 两者不同的提升。这个问题从解析阶段到运行阶段来说明。首先,在解析阶段 var 后面的 AA 会被提升然后 AA 被定义为undefined,BB 也会被提升,而BB被提升后的内容就是整个 function 里面的内容,其实从浏览器的控制台我们可以看出一二。然后,整个解析过程完了就到了运行阶段,在运行阶段期间,当读到 AA() 的时候,其实就是将 AA 这个变量指向function(){}这个函数然后调用,而到了 BB() 的时候,就会从之前声明的函数中去查找该早已经声明的函数,然后直接调用。

    复制代码
     1 var AA = function(){
     2    console.log(' AA_ 1 ');
     3 }
     4 
     5 AA(); // 输出 AA_1
     6 
     7 
     8 function AA(){
     9    console.log(' AA_2 ');
    10 }
    11 AA(); //输出 AA_2
    12 
    13 //这个例子就很好说明了 var 在运行阶段动态内建,而 function 在预解析阶段静态建立。
    复制代码



  • 相关阅读:
    POJ 3071 概率DP
    BZOJ 2427 /HAOI 2010 软件安装 tarjan缩点+树形DP
    POJ 1155 树形DP
    POJ 3252 组合数学?
    POJ 3641 快速幂
    POJ 3180 Tarjan
    POJ 3185 DFS
    POJ 3260 DP
    POJ 2392 DP
    99. Recover Binary Search Tree
  • 原文地址:https://www.cnblogs.com/shytong/p/5100426.html
Copyright © 2011-2022 走看看