• js作用域其二:预解析


    文章目錄

    解析机制

    JavaScript是一门解释型的语言 , 想要运行js代码需要两个阶段

    1. 编译阶段: 编译阶段就是我们常说的JavaScript预解析(预处理)阶段,在这个阶段JavaScript解释器将完成把JavaScript脚本代码转换到字节码
    2. 执行阶段: 在编译阶段JavaScript解释器借助执行环境把字节码生成机械码,并从上到下按顺序执行

    预解析时做什么

    var , function声明的变量提升

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

    1
    2
    3
    4
    5
    6
    7
    if( false ){
    var aa = 20;
    var bb = 30;
    }

    function (){};
    function BB(){};

    var定义的aa,bb以及function定义的AA(),BB()都会被变量提升到window对象下面 提升后等同于如下代码:

    1
    2
    3
    4
    5
    6
    7
    8
    var aa;
    var bb;
    function (){};
    function BB(){};
    if( false ){
    aa = 20;
    bb = 30;
    }

    注: 不是用var 定义的变量具有全局性, 但是并不会被提升, 只有在第一次执行到时才会出现在全局作用域中

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

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

    1
    2
    3
    4
    5
    AA();
    function (){};

    BB();
    var BB = function(){};

    AA();不会报错,因为是以function的变量提升,BB()会报错,因为是以var的变量提升,提升后代码等同于如下:

    1
    2
    3
    4
    5
    6
    function (){};
    var BB;

    AA();
    BB();
    BB = function(){};

    注意: 函数声明提升以后并不会执行内部的代码, 在其内的变量声明也不会起作用, 而是等到函数第一次被调用时才会执行 如:

    1
    2
    3
    4
    5
    6
    7
    var AA = function(){
    console.log(' AA ');
    }

    function BB(){
    console.log(' BB ');
    }

    单独这一段代码并不会起作用, 只有执行:

    1
    2
    AA(); // 输出 AA
    BB(); //输出 BB

    function 覆盖

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

    大专栏  js作用域其二:预解析ass="gutter">
    1
    2
    3
    4
    5
    6
    7
    8
    9
    AA();   // 输出 I am AA_2;
    function (){
    console.log('I am AA_1');
    };

    AA(); // 输出 I am AA_2;
    function AA(){
    console.log('I am AA_2');
    }

    提升后其代码等同于如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    function AA(){
    console.log('I am AA_1');
    }

    function AA(){
    console.log('I am AA_2');
    }

    AA();
    AA();

    可以看到这是正常的函数声明覆盖

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

    解析器将变量提升并不是将所有的变量都提升到window对象下面,其提升的原则是提升到变量运行的环境(变量生效的词法作用域)顶端

    1
    2
    3
    4
    5
    6
    7
    aa = "I am aa";
    function AA(){
    console.log(aa); // 输出 aa 是 undefined
    var aa = "I am aa in a function";
    console.log(aa); //输出 aa 是 I am aa in a function
    }
    AA();

    这里 aa 被变量提升,但是aa 没有被变量提升到 window下面,而是被提升到其运行的环境 (function(){ })() 中去,也就是等同于

    1
    2
    3
    4
    5
    6
    7
    8
    aa = "I am aa";
    function AA(){
    var aa;
    console.log(aa); // 输出 aa 是 undefined
    aa = "I am aa in a function";
    console.log(aa); //输出 aa 是 I am aa in a function
    }
    AA();

    JavaScript“预解析”分段进行

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    <script>
    AA(); // 输出 AA2;
    function AA(){
    console.log('AA1');
    }

    function AA(){
    console.log('AA2');
    }
    </script>


    <script>
    function AA(){
    console.log('AA3');
    }
    </script>

    上面例子说明function函数声明是分块的,然而至于var变量的提升经过反复验证是不分块的( 此处如有不同意见请指教 )

    参考

    javascript解析机制——预解析
    本文是在此篇博客的基础上进行了修改与扩充

  • 相关阅读:
    新买的电脑桌面只有回收站该做些什么
    不安装oracle客户端也可以使用pl/sql developer
    Win7上安装Oracle数据库
    忘记oracle的sys用户密码怎么修改
    UML中类之间的关系
    JAVAEE 是什么,如何获取各种规范jar包及各种规范的jar包源码
    PL/SQL Developer使用技巧、快捷键
    Windows 7上安装Microsoft Loopback Adapter(微软环回网卡)
    超棒的30款JS类库和工具
    HTTP协议
  • 原文地址:https://www.cnblogs.com/lijianming180/p/12239863.html
Copyright © 2020-2023  润新知