首先 为什么要了解预编译?

目的: 就是为了解决JS中关于作用域和作用域链相关所产⽣的一切问题。


我们要知道,JavaScript在执行一段代码的时候,并不是单单的解释一行执行一行。

而是在这之前需要经过几个步骤才能运行处JavaScript代码。

步骤:

1.语法分析:就是通篇检查你的代码有没有语法错误,有语法错误的话,程序是不会执行的。

2.预编译:函数执⾏之前要进⾏的⼀个步骤。

3.解释执行:也就是程序读一句执行一句。


那么预编译他的执行流程是怎样的呢?

一段代码执行前会生成GO或AO对象,那么如何判定生成的是GO还是AO呢?

下面我们来具体分析:

首先我们要知道两个对象:

Global object 全局执行期上下⽂(简称GO)

Activation Object 函数执行期上下⽂(简称AO)

顾名思义,那么GO就在全局作用域,AO在函数作用域。

至于什么是全局作用域和函数作用域我这里简单讲下

image


我们记住两个执行顺序口诀,在做几个例子,我们就能轻松知道JS预编译的执行流程了

GO对象

1.找变量声明

2.找函数声明

3.执行

AO对象

1.找函数的形参和变量声明

2.把实参赋值给形参

3.找函数声明

4.执行


例子1. 单纯只有GO对象

var a = 1;
function test() {
  console.log(2);
}
console.log(a);
计算步骤可以参考上面GO口诀
第一步 找变量a,
第二步 找函数声明test,
第三步 执行语句

GO = {
    a: undefined -> 1
    test: test() {...}// 函数只是定义,并没有执行,所以不看里面的代码
}

结果:当我们consoel.log(a)时,a的结果应该为1

例子2.有GO对象 和 AO对象

函数在定义的时候并没有产生AO, 而是在函数执行时(前一刻)才产生AO

在一个作用域中变量没有声明就赋值叫做暗示全局变量,会存到GO里面

var a = 1;
function test(b) {
  c = 1;
  var d = 2;
  console.log(a, b, c, d);
}

test(11);
GO 
第一步找变量声明a,
第二步找函数声明test
第三步执行语句

GO = {
    a: undefined -> 1,
    test: function () {...},
    c: 1
}




第一步找变量声明d, 和形参b,
第二步实参值11赋值给形参b,
第三步找函数声明,发现并没有函数声明。
第四步执行语句,发现c没有声明就赋值了,属于暗示全局变量(imply global variable) ,所以存到GO里面。

AO = {
    d: undefined -> 2,
    b: undefined -> 11,
    
}
结果:  console.log(a, b, c, d); 1, 11, 1, 2

image


例子3 有GO 和 AO 较复杂时

AO他⾃⼰有的他就找⾃己的自己没有的就去GO里面找(下节讲到作用域、作用域链时会证明)

函数声明和变量声明会提升

    
var b = 3;
console.log(a);// function a(a){...}
function a(a) {
  console.log(a);// function a() {}  函数声明会提升
  var a = 2;
  console.log(a);// 2
  function a() {}
  var b = 5;
  console.log(b);// 5 AO自己有的优先找自己,没有才会到GO找。

  if (b) {
    var c = 4;
  }
}
a();


GO = {
  b: undefined
  a: function a(a) {...}
}

AO = {
  a: undefined -> function a() {} -> 2
  b: undefined -> 5
  c: undefined -> 4
}

下面可以自己尝试下做下面的题目,分析出相应的GO AO。

在AO最后一步执行语句时,有return就返回了,并且终⽌函数运行。

题目1.

function test() {
    return a;
    a = 1;
    function a() {}
    var a = 2;
}

console.log(test());

题目2.

实参和形参是相互映射关系, 实参被修改形参也会跟着改变。

a = 1;
function test(e) {
    function e() {}
    arguments[0] = 2;
    console.log(e);
    if (a) {
      var b = 3;
    }
    var c;
    a = 4;
    console.log(b);
    f = 5;
    console.log(c);
    console.log(a);
}
var a;
test(1);
console.log(a);
console.log(f);