还原真实,javascript之预编译 / 预解析

今天在群里吹水时,有群友提出一个问题。我一看很简单,就立马给出了答案:由于存在变量提高,因此输出undefined。本觉得无人反驳,可确招来口诛笔伐。做为写实派的我,一向以来坚持真实是个人使命,岂能容忍这等虚头巴脑的言论攻击。遂以此文记之,本在还原真实。奈何文笔拙劣,恐表述不当,误人子弟。如有不当之处,还请众佬及时斧正,以正视听。javascript


就是下面这段代码:java

var obj = {
  say: function () {
      
      console.log(obj)

  }()
}

// 输出 undefined

为何是undefined?node

这个问题看似简单,不值一提,可其实是小孩没娘,说来话长!编程

尽管如此,我仍是长话短说。很简单,由于在javascript执行以前,是存在一个“预编译”或者说是“预解析”这样的过程,在这个过程中,进行了变量提高。浏览器

什么是变量提高?
变量提高就是将变量名提高到其所在做用域的顶部并赋值为undefined。与之相关的还有函数提高,不一样的是,函数提高是将函数名及函数体所有提高到其所在做用域的顶部编程语言

与其说“预编译”,“预解析”可能更合理一点。为何这样说?
由于在编程语言(如java,C#)当中,代码都是要先编译,后执行。而javascript做为脚本语言,不一样于编程语言的一点是没有编译过程,可是它须要脚本解释器边解析边执行,而脚本解释器在解释执行代码前会先扫描一遍,这个过程就是“预解析”过程。函数

那么为何会存在变量提高和函数提高呢?
在ES5当中,没有块级做用域的概念,只有全局做用域和函数做用域。声明变量能够用var关键字,也能够直接声明,只不过直接声明的变量是全局变量,而用var关键字声明的变量在全局做用域下就是全局变量,在函数体内就是局部变量。而且var关键字声明的变量在其所在的做用域下存在变量提高。code

em... 那变量提高跟上面的代码输出的结果是undefined有什么关系呢? 好,请坐下,陈独秀同窗。对象

咱们来用代码还原一下真实过程:ip

预解析阶段:
生成全局对象,浏览器当中是window对象,node环境下是global对象
变量提高:
全局做用域下,变量obj提高到顶部,直接挂在window对象下,至关于window.obj = undefined;
say方法是一个匿名函数。匿名函数的函数体赋值给了变量say。因此变量say也会进行变量提高,它所在的做用域也是全局window下,至关于window.say = undefined;

函数提高:

function(){ 
  console.log(obj);  //obj = window.obj = undefined
}

执行阶段:
1,建立一个执行上下文(execution context),函数压栈,生成active object(活动对象)
1,执行/解释上下文中的function,为变量赋值
2,

参考:https://www.jianshu.com/p/edb2be5866eb

  • 须要记住的是:
    • 变量提高只提高变量名,函数提高会提高函数名及其函数体。
    • 变量提示优先级大于函数提高优先级。也就是说无论变量声明在前仍是函数声明在前,都是先进行变量提高,再进行函数提高。

执行阶段:

function(){
  console.log(obj); //输出undefined
}()
相关文章
相关标签/搜索