“预编译”

“预编译”

我的老师在和我讲相关知识点前和我说过这么一个笑话:

面试时我因为这么一个问题挂了

var a = 100
function foo(){
    console.log(a)
}
foo()
 

问:为什么输出a的值是100?
答:因为100赋值给了a。

老师说完我头昏脑涨,完全不明白笑点在哪,后来才知道这是在考察“预编译”这方面的知识。
总的来说,“预编译”可以分为

  1. 创建GO对象(global object) 发生在页面加载完成时
  2. 创建AO对象(activation object) 发生在函数执行前一刻

具体步骤如下:

全局预编译
1. 创建GO对象
2. 找变量声明,将变量声明作为GO对象的属性名,并赋值undefined
3. 找全局里的函数声明,将函数名作为GO对象的属性名,值赋予函数体

  

局部预编译
1. 创建一个AO对象
2. 找形参和变量声明,将形参和变量声明作为AO对象的属性名,值为undefined
3. 将实参和形参统一
4. 在函数体里找函数声明,将函数名作为AO对象的属性名,值赋予函数体

所以那个笑话里的面试问题我们应该这么回答:

首先,编译器创建一个GO对象
找到变量声明 var a
和函数声明 function foo(){}
将上面两个变量声明作为GO的属性名赋初值
GO{
    a:undefined
    foo:function(){}
}
然后运行第一行代码 a=100
在GO中将100赋值给a
再执行第五行代码运行foo函数
创建一个AO对象
在函数体内找变量声明和形参,(无)
再在函数体内找函数声明(无)
所以
AO{
    
}
完成后运行第三行代码,输出a
先在AO对象中寻找a的值,发现不存在,向外部作用域扩展,在GO对象中寻找a,发现a的值为100
输出100

复制代码

当然,笑话里的题过于简单,但是能让我们清晰的了解到这个“预编译”的进行
下面,我们来看一道面试题简化版,练练手:

global = 100
    function fn() {
      console.log(global); 
      global = 200
      console.log(global); 
      var global = 300
    }
    fn()

它的逻辑和输出结果是多少呢?通过一步步的分析我们可以知道具体的分析应该是这样的:

GO: {
      global: undefined => 100,
      fn: function() {}
    }
    global = 100 // 没有声明的变量默认为全局变量,也会放到GO中
    function fn() {
      console.log(global); // 输出undefined
      global = 200
      console.log(global); // 输出200
      var global = 300
    }
    AO: {
      global: undefined => 200 => 300
    }
    fn()

 



转自:https://juejin.cn/post/6954393788001288199

posted @ 2021-04-27 11:46  一个动态类型的幽灵  阅读(130)  评论(0编辑  收藏  举报