JavaScript之详解预编译

前言


首先JavaScript这个预编译和传统的编译是不一样的(可以把js预编译理解为特殊的编译过程)

前面我们在讲JavaScript的作用域时提到了预编译,今天我就介绍一下预编译。 学好一门语言我们一定要知道该语言的运行机制。

JavaScript代码在运行时,首先会进行语法分析,通篇检查代码是否存在低级错误,然后进行预编译,整理内部的一个逻辑,最后再解释执行开始一行一行的执行代码

一. 语法分析

先全部扫一遍 看有没有语法错误,比如小括号(),花括号{}的缺失,或者是标点符号在中英文的状态下不对。

二. 预编译(执行前一刻)

变量 声明提升 函数声明整体提升。划重点,是变量声明和函数声明。

1、预编译前奏


  • 暗示全局变量

任何变量,如果变量未经声明就赋值,此变量就为全局对象所有。

例如: a = 123;

上面的变量a 未经声明就赋值了,所以变量a是全局对象所有。

  • 一切声明的全局变量,全是window的属性

例如:var a = 123; ===> window.a = 123

变量a是全局变量,所以也是window对象的属性。


2、预编译


函数中:预编译执行四部曲
  • 创建AO对象 (Activation Object (执行期上下文))
  • 找形参和变量声明,将变量和形参名作为AO属性名,值为undefined
  • 将实参值和形参统一
  • 在函数体里面找函数声明,值赋予函数体
全局中:预编译三部曲
  • 创建GO对象(Global Object window就是全局)
  • 找变量声明,将变量声明作为GO对象的属性名,值赋予undifined
  • 找全局里的函数声明,将函数名作为GO对象的属性名,值赋予函数体

三. 解释执行

预编译完成过后,解释一行执行一行

实例分析

<script>
    var a = 1;
    console.log(a);
    function test(a) {
        console.log(a);
        var a = 123;
        console.log(a);
        function a() {}
        console.log(a);
        var b = function() {}
        console.log(b);
        function d() {}
    }
    var c = function (){
        console.log("I at C function");
    }
    console.log(c);
    test(2);
</script>

分析过程如下:

  1. 页面产生便创建GO全局对象(Global Object)(也就是window对象);
  2. 第一个脚本文件加载;
  3. 脚本加载完毕后,分析语法是否合法;
  4. 开始预编译
  • 查找变量声明,作为GO属性,值赋予undefined;
  • 查找函数声明,作为GO属性,值赋予函数体;
  • 在预编译过程中,变量声明出现同名不覆盖,变量声明与函数声明同名,变量声明不能覆盖函数声明,函数声明直接覆盖变量声明,值为函数体。

全局预编译结束后,GO中存储的值
如下所示:

GO/window = {
        a: undefined,
        c: undefined,
        test: function(a) {
            console.log(a);
            var a = 123;
            console.log(a);
            function a() {}
            console.log(a);
            var b = function() {}
            console.log(b);
            function d() {}
        }
    }

解释执行代码(直到执行完test(2)语句)

GO/window = {
        a: 1,
        c: function (){
            console.log("I at C function");
        }
        test: function(a) {
            console.log(a);
            var a = 123;
            console.log(a);
            function a() {}
            console.log(a);
            var b = function() {}
            console.log(b);
            function d() {}
        }
    }

执行函数test()之前,再次发生预编译,(此时是函数体执行之前产生的AO对象)

预编译第一和第二两小步如下:


    AO = {
        a:undefined,
        b:undefined,
    }

预编译之第3步如下:


    AO = {
        a:123,
        b:undefined,
    }

预编译之第4步如下:


    AO = {
        a:function a() {},
        b:undefined
        d:function d() {}
    }

执行test()函数时如下过程变化:


    AO = {
        a:function a() {},
        b:undefined
        d:function d() {}
    }
    --->
    AO = {
        a:123,
        b:undefined
        d:function d() {}
    }
    --->
    AO = {
        a:123,
        b:function() {}
        d:function d() {}
    }

最后的执行结果 :

	1
	fn:c
	fn:a
	123
	123
	fn:b
文章是笔者分享的学习笔记,若你觉得可以、还行、过得去、甚至不太差的话,可以“推荐”一下的哦。就此谢过!
  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值