参考文献:https://blog.csdn.net/q1056843325/article/details/52951114

JavaScript引擎运行的三大步骤

  • 语法分析。
  • 预编译(第一次\前置扫描)
  • 解释执行(第二次扫描)

严格说Js是解释性语言、没有编译即使有JIT也是V8引擎做的,JS预编译是第一次扫描把声明的东西变量放在名字表里。

脚本大概步骤

创建全局对象GO(window) (上下文)

加载脚本文件

预编译:

  • 找出所有的变量声明,按照变量名加入全局对象,如果已经存在,忽略。
  • 找出所有的函数声明,按照函数名加入全局对象,如果已经存在同名变量或者函数,替换(后面会覆盖前面的函数或变量)。
  • 非声明不予理睬

解释执行。

注意:函数的预编译在调用的时候先执行预编译。

预编译、举例子1

<script>
//Javascript脚本的预编译
    //1.没有var的变量,全部认为是window的全局变量,不参与预编译
    console.log(aa);
    aa=5;
    console.log(aa);
</script>

结果:Uncaught ReferenceError: aa is not defined

原因:在预编中没有发现任何东西,在执行中第一个console.log打印aa的时候aa没有被定义,所以包语法错误。

//Javascript脚本的预编译
    //1.没有var的变量,全部认为是window的全局变量,不参与预编译
    console.log(aa); //undefined
    var aa=5;
    console.log(aa); //5

原因:1、生成了全局对象GO、然后开始扫描找到变量和函数声明并加入全局对象中,2、开始解释执行,因为在预编中aa已经加入GO对象中、但并没有初始化,所以第一个console.log()出现了undefined在,在下一行aa被赋值成5,所以一个console.log结果是5。这种机制有个好处就是,在函数定义后可以在函数的前面进行调用。

预编译、举例子2

//Javascript脚本的预编译
    //2.即使在函数中,a也是全局变量、是运行时,不是定义时。
    function test(){
        a=5;
    }
    console.log(a);

Uncaught ReferenceError: a is not defined,

原因:同上面,1、预编译的时候扫到了test这个函数,但没有扫到a。执行的时候test没有调用,console.log的时候a没有定义所以出错

<script>
//Javascript脚本的预编译
    //2.即使在函数中,a也是全局变量、是运行时,不是定义时。
    test();
    function test(){
        a=5;
    }
    console.log(a); //5
</script>

结果是 :5

原因:1、第一次预编译的时候扫描到了test函数声明,没有扫到a。2.执行test()函数,函数进行预编译,函数预编译没有结果。执行时window对象下加入了a全局变量并赋值等于5,函数销毁。执行console.log时结果等于5。

//Javascript脚本的预编译
    //2.即使在函数中,a也是全局变量、是运行时,不是定义时。
    test();
    function test(){
      var  a=5;
    }
    console.log(a); //Uncaught ReferenceError: a is not defined,

原因:同第二个demo中的第一个一样的错误,因为函数执行中进行了预编译和解释执行,但函数声明周期销毁var a也销毁了,所以a报了错误。====此问题涉及到了作用域链的问题

补充:脚本中,所有变量声明,在脚本的预编译阶段完成,所有变量的声明与实际的书写位置无关

预编译、举例子3

<script>
    console.log(haha);
    function haha(){
        console.log('h1');
    }
</script>

图

结果:把函数打印出来了。原因和例子1是一样的。

补充:脚本中,所有函数声明,在脚本的预编译阶段完成,所有函数的声明与实际的书写位置无关。脚本中如果函数和变量同名、那么函数会覆盖变量、只有函数能覆盖变量、变量无法覆盖函数。

<script>
    console.log(haha);
    var haha="123";
    function haha(){
        console.log('h1');
    }
    var haha="321";
</script>

脚本中,后面的函数声明会覆盖前面的函数声明,并且忽略参数

<script>
    console.log(haha);
    function haha(a){
        console.log('haha1');
    }

    function haha(a,b){
        console.log('haha2');
    }
</script>

图

Last modification:January 30, 2020
如果觉得我的文章对你有用,请随意赞赏