js预编译的四部曲

  • Post author:
  • Post category:其他

学习到了一些关于预编译和作用域的知识和大家分享一下!

众所周知javascript是解释性语言,主要特点为解释一行执行一行。

而在js运行时会进行三件事:1语法分析  2.预编译  3.解释执行

    语法分析会在代码执行前对代码进行通篇检查,以排除一些低级错误

    预编译发生在代码执行的前一刻

    解释执行顾名思义就是执行代码

我先给大家举几个预编译的小例子:

        var a = 123;

console.log(a); 

此时他返回的值会是123;

   但如果我们调换位置:

          console.log(a);

          var a = 123;      

          我们得到的结果便会是undefined。(由于js解释性语言的原因,先执行console.log,而由于预编译的原因浏览器并不会报错)

如果我们在次尝试不定义变量直接获取:

                console.log(a);  此时我们会发现浏览器会进行报错。//Uncaught ReferenceError: a is not defined

                                                                                                               这条语句提示我们a没有定义

到这里有些人会有疑问为什么在console.log前,后和不定义a会有如此大的差别,这就是预编译起到的作用

 

在具体讲解预编译之前要先帮大家了解几点小知识,如下:

预编译的前奏

   1. imply global 暗示全局变量:即任何变量,如果变量未经声明就赋值,此变量就为全局对象(window)所有。

              简单解释起来就是,如果在js中我们在赋值时经常先定义一个变量,如:var a = 123;

              此时123这个数字便被赋予了a这个变量,此时我们在控制台console.log(a)就会得到a的值123;

              这时就会我们就会有个疑问,如果我们没有定义变量直接进行赋值还会打印出值么。

              答案是肯定的,此时如果我们未定义变量直接赋值,如:

                b = 456;

            此时a会被认为是全局的一个对象,即window下的一个值,此时我们在控制台下console.log(b)同样可以得到b的值456。

            此时我们可以认为    b = 123   ————>   window.b  =456

   2. 一切声明的全局变量,全是window。

            简单说明就是我们 var  c = 789   ===>    window.c = 789(即:c =789)

 

预编译(粗浅版本)

下面我们来看一下对预编译最基本的肤浅理解(该理解非常粗浅无法解决复杂问题):

    函数声明整体提升   

    变量,声明提升

个人理解:在函数执行前函数声明(function(){})会整体提升至逻辑的最前方,

                 变量则会把自身的声明提升到程序的最最前方。

//注释  var  a =123;是变量声明+赋值

    var  a:变量声明

    a  = 123 变量赋值

    在预编译时我们不看赋值,只把变量的声明提升,因此若在赋值前打印会提示undefined;

此时我们就可以理解之前的问题了:

        先打印再定义:

                    console.log(a);

                    var a = 123;  

在执行前var  a提升至代码的最最前端 ,提升后我们再打印 a,由于此时a未被赋值因此打印提示undefined。

 

                     console.log(a);

      不定义:

                    console.log(a);

  此时由于没有a的定义,所以会报错提示a is not defined;即:a未定义。

看似很好理解但是如果代码稍微复杂便无法解决,例如:

            console.log(a);   fun

            function a(a) {

                        var  a  =  456;

                        var  a   =function  ()  {

                }

                       a();

            }

                    var  a  =   123;

 

下面我们来看一下真正的预编译:

预编译(精装版本):

    预编译的四部曲:

        1.创建GO/AO对象
        2.找形参和变量声明,将变量和形参名作为AO属性名,值为undefined
        3.将实参值和形参统一

        4.在函数体里面找函数声明,值赋予函数体

 

以此为例:

  再次函数中我们来进行预编译:
      1.创建AO对象:我们隐式的在函数中创建了一个AO的对象来盛放函数中的变量,此时对象中并没有值;

       2.找形参和变量声明,将变量和形参名作为AO属性名,值为undefined:我们在第二个过程中需按照变量和形参

                           

      3.将实参值和形参统一:此时将实参带入函数中由于在函数外 f(1),因此AO中a = 1

                           

    4.在函数体里面找函数声明,值赋予函数体:由于在函数中有 function a() {} ,这一函数因此此时AO中 a = function a() {}

                           

                          

在进行完预编译后此时若执行函数则会以AO为基础对函数中的变量进行赋值:此时函数中有两次打印一次在函数开头,一次在函数为a赋值之后

再赋值前由于AO中值不变因此a所打印出的值为 function a() {}

在赋值后AO中a = 123,所以此时打印出的值为123

                                           

 

 

 

 

 

    

 

 

 

 

 

 

 


版权声明:本文为Bombas原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。