JavaScript预编译过程

  • 阶段(三个)
  • 预编译过程
    • 1. JavaScript代码执行之前的预编译
      • 案例说明
    • 2. 函数执行前的预编译
      • 案例说明
  • 总结
    • 预编译两个小规则:
    • 预编译前奏

阶段(三个)

  1. 词法语法分析:词法语法分析就是检查JavaScript代码是否有一些低级的语法错误
  2. 预编译:本文主讲
  3. 执行代码:执行代码就是js引擎解析代码,解析一行执行一行

这章主要讲预编译过程

预编译过程

预编译也分为2个时间点:

  1. 第一个是在JavaScript代码执行之前
  2. 第二个是在函数执行之前。

但是JavaScript代码之前,之前的预编译只发生一次,函数执行之前的预编译是多次的。

1. JavaScript代码执行之前的预编译

  1. JavaScript代码执行之前,首先会创建一个全局对象,可以理解为window对象,也可以理解为GOGlobal Object)对象,我们是看不到的(无法打印)
  2. 然后将所有声明的全局变量未使用varlet声明的变量放到GO对象中,并且赋值为undefined(联想到“变量提升”)
  3. 分析**函数声明:**然后再将所有的函数声明也放到GO对象中,并且赋值为函数自身的函数体(函数名为属性名,值为函数体,如果函数名和变量名相同,则无情覆盖)

案例说明

<script>var a = 1;console.log(a);console.log(b);var b = 10;function fun (a) {console.log(b);var a = b = 2;var c = 123;console.log(a);console.log(b);}var a2 = 20fun(1);</script>

结合上面说的步骤:

  1. 首先,<script></script>中的代码执行之前会创建一个GO对象(window对象)

    GO = {//自带的属性都不写
    }
    
  2. 将所有声明的全局变量、未使用varlet声明的变量放到GO对象中,并且赋值为undefined

    GO = {a : undefined,b : undefined,a2 : undefined
    }
    
  3. 分析函数声明,函数名为属性名,值为函数体,如果函数名和变量名相同,则无情覆盖

    GO = {a : undefined,b : undefined,a2 : undefined,function fun (a) {var a = b = 2;var c = 123;}
    }
    
  4. 此时完成了js代码执行之前的预编译过程,开始执行js代码,首先是给a进行赋值为1,在GO对象里边也会进行对应的改变:

    GO = {a : 1,b : undefined,a2 : undefined,function fun (a) {var a = b = 2;var c = 123;}
    }
    
  5. 然后打印a,此时会在GO对象上去找变量a,然后此时的a的值为1,所以console.log(a) 是等于1的。接着打印b,也会去GO对象上找,找到了b的值为undefined,所以console.log(b)是等于undefined

  6. 接着执行到赋值语句:b = 10; 此时GO对象里b的值变成了10

    GO = {a : 1,b : 10,a2 : undefined,function fun (a) {var a = b = 2;var c = 123;}
    }
    
  7. 接着下一行代码是一个**fun函数,此时不会去执行该函数**,因为在前面的预编译过程中实际上是被放到了代码的最前端,就是传说中的声明提前,所以忽略掉了。接着给a2进行赋值操作a2 = 20,GO对象也发生变化:

    GO = {a : 1,b : 10,a2 : 20,function fun (a) {var a = b = 2;var c = 123;}
    }
    
  8. 接着是执行fun函数,如上面说到的另外一个时间点发生的预编译,就是执行函数之前,现在就来说一下函数执行前的预编译是怎么样的。

2. 函数执行前的预编译

  1. 函数调用,也是会生成自己的作用域(**AO:**Activetion Object,执行期上下文)AO活动对象。函数调用时候,执行前的一瞬间产生的,如果有多个函数的调用,会产生多个AO

    1. 生成AO对象:函数执行前的一瞬间,生成AO活动对象
    2. 分析生成AO属性:查找形参变量声明放到AO对象,赋值为undefined
    3. 分析函数声明:查找函数声明放到AO对象并赋值为函数体。函数名为属性名,值为函数体;

    如果遇到AO对象上属性同名,则无情覆盖

  2. 逐行执行。

案例说明

拿的是上文中的代码示例。

  1. 第一步创建AO对象

    AO{}
    
  2. 查找形参变量声明放到AO对象并赋值为undefined

    注意:fun函数里边的b是未经var声明的,所以是全局变量,不会被放在fun的AO上。

    AO{a: undefined,//形参a与局部变量a同名c: undefined
    }
    
  3. 实参赋值到形参

    AO{a: 1,c: undefined,
    }
    
  4. 查找函数声明放到AO对象并赋值为函数体,fun函数没有函数声明,所以忽略这一步。

  5. 函数执行之前的预编译完成,开始执行语句

  6. 执行代码

    1. 首先执行打印变量b,而此时fun的AO里边并没有变量b,所以会去GO对象里边找,此时的GO对象b的值为10,所以第一行代码打印出10;

    2. 第二行代码首先要看的是b = 2,然后GO对象里边b的值就被改为2了。

      GO = {a : 1,b : 10,a2 : 20,function fun (a) {var a = b = 2;var c = 123;}
      }
      
    3. 然后b再赋值给a,变量a是属于局部变量a,所以fun的AO对象里边a的值被改为2。

      AO{a: 2,c: undefined,
      }
      
    4. 接着下一个赋值语句是c = 123,所以AO对象中c的值被改为了123

      AO{a: 2,c: 123,
      }
      
    5. 此时再执行console.log(a)的值就是AO对象里边a的值 2;执行console.log(b)的值就是GO对象b的值 2,至此函数fun执行完毕,紧跟着fun的AO也会被销毁

  7. 综上所述,依次打印出来的值为:1,undefined,10,2,2

总结

预编译两个小规则:

  1. 函数声明整体提升(无论函数调用和声明的位置是前是后,系统总会把函数声明移到调用前面)
  2. 变量声明提升(无论变量调用和声明的位置是前是后,系统总会把声明移到调用前,注意仅仅只是声明,所以值是undefined

预编译前奏

  1. imply global(暗示全局变量-专业术语) 即:任何变量,如果未经声明就赋值,则此变量就位全局变量所有。(全局域就是window,这里再一次说明了JavaScript是基于对象的语言,base on window)
  2. 一切声明的全局变量,全是window的属性;var a=12;等同于window.a = 12;(会造成window这个对象特别臃肿)
  3. 函数预编译发生在函数执行前一刻(懒加载机制)

JavaScript预编译过程相关推荐

  1. 5单个编译总会编译全部_5分钟读懂JavaScript预编译

    大家都知道JavaScript是解释型语言,既然是解释型语言,就是编译一行,执行一行,那又何来预编译一说呢?脚本执行js引擎都做了什么呢?今天我们就来看看吧. 1-JavaScript运行三部曲 语法 ...

  2. js中立即执行函数会预编译吗_JavaScript预编译过程

    什么是预编译? 当js代码执行时有三个步骤: 1.语法分析,这个过程检查出基本的语法错误. 2,预编译,为对象分配空间. 3,解释执行,解释一行执行一行,一旦出错立即停止执行. 预编译发生在代码执行的 ...

  3. C语言的预编译,程序员必须懂的知识!【预编译指令】【预编译过程】

    由"源代码"到"可执行文件"的过程包括四个步骤:预编译.编译.汇编.链接.所以,首先就应该清楚的首要问题就是:预编译只是对程序的文本起作用,换句话说就是,预编译 ...

  4. JavaScript预编译

    前言:在JavaScript中存在一种预编译的机制,这也是Java等一些语言中没有的特性,也就正是因为这个预编译的机制,导致了js中变量提升的一些问题,下面这两句话能解决开发当中一部份问题,但不能解决 ...

  5. JavaScript作用域原理——预编译

    JavaScript是一种脚本语言, 它的执行过程, 是一种翻译执行的过程.并且JavaScript是有预编译过程的,在执行每一段脚本代码之前, 都会首先处理var关键字和function定义式(函数 ...

  6. Javascript作用域原理---预编译

    问题的提出 首先看一个例子: var name = 'laruence'; function echo() { alert(name); var name = 'eve'; alert(name); ...

  7. ASP.NET 网站预编译概述

    默认情况下,在用户首次请求资源(如网站的一个页)时,将动态编译 ASP.NET 网页和代码文件.第一次编译页和代码文件之后,会缓存编译后的资源,这样将大大提高随后对同一页提出的请求的效率. ASP.N ...

  8. 【C 语言】编译过程 分析 ( 预处理 | 编译 | 汇编 | 链接 | 宏定义 | 条件编译 | 编译器指示字 )

    相关文章链接 : 1.[嵌入式开发]C语言 指针数组 多维数组 2.[嵌入式开发]C语言 命令行参数 函数指针 gdb调试 3.[嵌入式开发]C语言 结构体相关 的 函数 指针 数组 4.[嵌入式开发 ...

  9. iOS底层探索(二) - 写给小白看的Clang编译过程原理

    iOS底层探索(一) - 从零开始认识Clang与LLVM 写在前面 编译器是属于底层知识,在日常开发中少有涉及,但在我的印象中,越接近底层是越需要编程基本功,也是越复杂的.但要想提升技术却始终绕不开 ...

最新文章

  1. c#.net调用pdf2swf.exe将pdf文件转换为swf,vs中运行正常,布署IIS服务器部署转换后文字部分为空白...
  2. LeetCode实战:有效的括号
  3. 香港大学顾佳涛:非自回归神经机器翻译 | 直播预告
  4. 【转】DICOM命令集和数据集解析!!
  5. 剑指Offer - 面试题7. 重建二叉树(递归)
  6. win10新版本被移除的旧特性
  7. mac 下安装java, jmeter, ant, jenkins,使用jmeter+ant+jenkins 接口测试集成工具,发送html报告到邮箱中
  8. hdu 4928 Series 2 (优化+模拟)
  9. html音乐播放心得体会,音乐心得体会
  10. linux上复制文件命令是什么,Linux复制文件用什么命令怎么用
  11. python idle是什么_idle是什么意思
  12. Appium swip滑动
  13. 如何在MacBook Pro上使用原彩显示功能?
  14. 什么是signal(SIGCHLD, SIG_IGN)函数
  15. 《C语言实战教学》:程序式思维及C语言介绍
  16. 今日宜募捐?刘强东、李彦宏清北壕捐大PK
  17. VS源文件提取工具vsjuicer 实现细节
  18. 5G加速,为什么说紫光股份是运营商市场的大赢家?
  19. 如何提高Alexa排名
  20. css垂直居中和水平居中方法总结

热门文章

  1. 你知道哪些常用快捷键?电脑快捷键大全,打工人必备!
  2. ERROR: Could not find a version that satisfies the requirement matplotlib (from versions: none) ERRO
  3. 成都物韵电子商务有限公司代运营入驻电商平台需要注意哪些问题?
  4. 记录一下前端常用的一些网站地址
  5. 二次开发 外包项目利器 springmvc SSM后台框架源码
  6. 盘点那些高大上的量化择时方法都有哪些?
  7. 为什么传统的基于硬件的频谱分析仪不适用于当今的频谱监测—介绍软件定义的频谱分析
  8. linux下DNF命令使用
  9. [文本对比工具] Beyond Compare
  10. Java IDE MyEclipse 使用教程:创建Web服务项目