JS预编译

  1. 作用域的创建阶段—预编译的阶段
  2. (局部)预编译时做了那些事情:
    1. 创建AO对象 供js引擎自己去访问
    2. 找形参和变量的声明,作为ao对象的属性名,值是undefined
    3. 实参和形参相统一
    4. 找函数声明,会覆盖变量的声明
// 函数
    function fn(a){
        console.log(a); //function a(){}
        // 变量声明+变量赋值(只提升变量声明,不提升变量赋值)
        var a = 123;
        console.log(a); //123
        // 函数声明
        function a(){};
        console.log(a); //123
        // 函数表达式 不是函数声明所以无需编译
        var b = function x(){};
        //function b(){} //这种情况就是b:undefined function b(){}
        console.log(b);//function(){}
        // 函数
        function d(){};
    }
    //调用函数
    fn(1);

    //分析过程
    // AO{
    //     a:undefined 1 function a(){}
    //     b:undefined
    //     d:function d(){}
    // }
  1. 全局预编译的3个步骤:
    1. 创建GO对象(Global Object)全局对象。
    2. 找变量声明,将变量名作为GO属性名,值为undefined
    3. 查找函数声明,作为GO属性,值赋予函数体
console.log(global)//function global() {}
    global = 100;
    function test(){
        console.log(global);		// 根据AO对象中的数据(预编译就已经创建了,所以不会在到GO里找):undefined
        var global = 200;		// 执行到这时,200覆盖了undefined
        console.log(global);		// 200
        var global = 300;
    }

    console.log(global)//100
    function global() {}
    console.log(global)//100
    test();
    var global;

    //分析过程
    //先GO,再AO
    // GO{
    //     global:undefined function global() {}
    //     test:function test() {}
    // }
    // AO{
    //     global:undefined
    // }

补充

关于GO对象和AO对象,它们俩是一个种链式关系,就拿上面的这个例子来说吧,如果在函数体的内部没有定义global变量,这也意味着AO对象中将有这个global这个属性。那如果没有会怎么办?它会去GO对象中寻找,说白了也就是一种就近原则。
tip
https://zhuanlan.zhihu.com/p/50236805