理解JavaScript的预编译

不要因为真相很难理解就不告诉我真相是什么

也不知道最开始是在哪个老师还是哪本书或者是哪个同学那里听来的,或者说学来的说js是一门不需要编译的语言,由浏览器直接解释执行。嗯很好理解嘛,当时觉得也很对,写完一个js文件引入到html中直接扔浏览器里面跑就OK了,并没有像Java那样要做一个javac hello.java 得到一个hello.class的编译步骤。但是当我学到es6的时候就彻底懵逼了,es6中的的模块章节中通篇都在讲述import 和 expert这两个风骚到飞起的指令的各种花样解锁姿势,各种引用,其中很重要很基本的一个概念就是它跟node中require的区别?区别是什么呢,就是es6中的import是编译时加载的,而node中的require是运行时加载的。还有另一个说法就是,es6中的import是静态编译阶段执行的,所以在你import的代码中不可以写任何的一丝一毫的js逻辑判断或者运算的代码。比如阮老师告诉我们

      import { 'f' + 'oo' } from 'my_module';   

这样写会报错,原因是import 是静态执行的而 大括号中的加法代码是运行时的操作,所以报错了。
大神们对于自己理解的知识说起来总是一笔带过,从不关心屌丝们对于一个概念为什么是这样的可能都不懂。
自己就曾在这里钻过很长时间的牛角尖,偏执于大家信口拈来的 ‘编译时’ 这个概念到底是发生在什么时候? 它都做了什么工作?
后来在看了一些书籍以及度娘之后终于有所领悟,为防止自己日后再次遗忘,特别记录在这里。
其实对于js的编译期或者说预编译,我自己是一直都知道的,只是自己没有把这个 动作 跟j s的编译联系到一块儿而已。直接上例子🌰

剧透: 其实你想象js中的hosting(变量提升)就懂了

理解预编译首先要弄清楚两个概念: 函数声明变量赋值

  function xiaoyu() {}   // 函数声明  

这种形式的写法是函数声明,也即是声明一个函数,这种写法,脚本在执行之前会做预编译处理(这里很重要哦,要记得函数声明是会有一个高的优先级的先编译后执行)

再来看另一种写法:

  var xiaoyu = function() {}    // 变量赋值

这种写法就属于是变量的赋值了,函数在js中也是一种数据,匿名函数作为变量赋值给定义的变量。这种形式的写法,在编译阶段也会做处理,但是!只会给变量xiaoyu分配一个内存空间,不会初始化(好吧,初始化为undefined了)具体值的初始化是在程序执行阶段。
好了接下来就可以正式看例子了:

        🌰1:
      function xiaoyu() {
        alert('xiaoyu')
      }
      xiaoyu()
      function xiaoyu() {
        alert('xiaoyu2')
      }
      xiaoyu()

分析这段代码,首先判断两个都属于是函数声明,都会在预编译阶段处理,而函数名相同,后面声明的会覆盖前面的在执行阶段就只会看到后面的。所以将代码复制到控制台执行会看到两个xiaoyu2

      🌰2:
      var xiaoyu = function () {alert('xiaoyu')}
      xiaoyu()
      xiaoyu = function(){alert('xiaoyu2')}
      xiaoyu()

分析代码,首先判断两个都属于是变量赋值,而且两个变量名一样,所以在编译阶段只会分配一个内存空间存放变量xiaoyu的内容,当代码执行时候按照顺序执行和赋值,会先后弹出xiaoyu 和xiaoyu2

      var xiaoyu    // undefined
      xiaoyu = function () {alert('xiaoyu')}
      xiaoyu() //   'xiaoyu'
      xiaoyu = function(){alert('xiaoyu2')}
      xiaoyu() // 'xiaoyu2'
      明白了吧

      🌰3:
      function xiaoyu() {alert('xiaoyu')}
      xiaoyu()
      xiaoyu = function() {alert('xiaoyu2')}
      xiaoyu()

分析代码,首先第一个属于函数声明,后一种属于变量赋值。所以预编译处理完后代码应该是这样的:

      var   xiaoyu   // undefined
      function xiaoyu() {alert('xiaoyu')}
      xiaoyu()    //   'xiaoyu'
      xiaoyu = function() {alert('xiaoyu2')}
      xiaoyu()   // 'xiaoyu2'
      🌰4:
      window.alert(xiaoyu)
      function xiaoyu() {}
      window.alert(xiaoyu)
      var xiaoyu = 123

以上代码编译结束应该是这样的:

      var xiaoyu   // undefined
      function xiaoyu () {alert('xiaoyu')}
      window.alert(xiaoyu)   //  function xiaoyu() {}
      window.alert(xiaoyu)  // function xiaoyu() {}
      xiaoyu = 123

总结可以得出,函数声明和变量声明会在预编译阶段被’提升‘并且变量的提升是被最优先的提升的,也就是说如果一个函数声明一个和一个变量同名了比如例子三中的那么变量名会被优先提升到最高 var xiaoyu // 不赋值 为undefined 然后提升函数声明 function xiaoyu() {alert('xiaoyu')} // 此时因为函数声明在后所以它覆盖了xiaoyu变量给它复制为一个函数。当js引擎做完所有的这些提升的工作后js才会按照代码顺序来执行。

另外需要注意的是 js不是全文编译完成再执行,而是块编译,即一个script块中预编译然后执行,再按顺序预编译下一个script块再执行 但是此时上一个script快中的数据都是可用的了,而下一个块中的函数和变量则是不可用的。

OK 讲到这里,是不是有点懂得es6中大编译时执行是什么意思了,它就是在代码执行前做的一个预编译也可以叫做静态编译,好处是让你可以在执行任何代码前预初始化更多的模块结构,这样如果引用尚未赋值的export,能得到更好的错误信息。例如,一个let绑定会扔出异常——如果你在它被赋值之前就引用它的话——你可以得到清晰的错误信息。而一个动态模块对象上的属性如果还未赋值就被引用,得到的是undefined,最终错误可能发生在客户代码中,必须跟踪这个错误直到源头——这比异常要难调试太多了。

累了,先写到这里

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,561评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,218评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,162评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,470评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,550评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,806评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,951评论 3 407
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,712评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,166评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,510评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,643评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,306评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,930评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,745评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,983评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,351评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,509评论 2 348