javascript中的预编译

120 阅读5分钟

预编译也是js中非常重要的概念之一,看完了成哥的js课程中的预编译后,我不敢说十分的清除,也敢说有个六七分的掌握啦~今天自己总结一下自己的所学,与大家分享,有不对的地方还请不吝赐教:)

预编译的规则

请牢记以下规则:

  • 函数声明整体提升
  • 变量仅声明提升(赋值不提升)
  • 当函数声明和变量重名时,只生产一个变量

举个栗子吧:

// 1. 函数声明整体提升
testFn(); //123
function testFn() {
    console.log(123);
}

//2. 变量仅声明提升(赋值不提升)
console.log(a);// 声明并赋值 undefined
var a = 1;
console.log(a);// 1
// consol.log(b); //未声明,报错 Uncaught ReferenceError: consol is not defined

// 3. 函数及变量重名时---覆盖
console.log(demo);// 函数demo
function demo(demo) {
    var demo = 2211;
    var demo = function () {
        console.log("demo()-demo()")
    } 
    console.log("demo");
}
var demo = 1122;
console.log(demo);// 1122

函数环境中的预编译

一、请牢记以下规则

  1. 创建AO对象 (活跃对象 activation object 执行期上下文)
  2. 找形参和变量声明,将形参名和变量作为AO对象的属性名,值为undefined
  3. 将实参值和形参统一
  4. 在函数体里面找函数声明,值赋予函数体 这样看或许不太好理解,还是举栗子吧:
function fn(a) {
    console.log(a);//AO.a function a() { console.log("a") }   
    var a = 123;  
    console.log(a);//123
    function a() { console.log("a") }//预编译处理过的就不用看了
    console.log(a);//123
    var b = function () { console.log("b"); }
    console.log(b);//AO.b function(){ console.log("b"); }
    function d() { console.log("d"); }
}
fn(100);

没学过预编译的时候,我真的一头雾水,一堆的a、b、c、变量、函数,到底哪个是哪个,现在请还不懂的你跟着我的思路:

第一步:创建一个AO对象。

AO = {}

第二步:找到所有形参和变量名,作为AO的属性,且值为undefined。

AO = {
    a:undefined
    b:undefined
}

第三步:统一实参和形参。

// 实参只有一个:100
// 形参只有一个:a
AO = {
    a:100,
    b:undefined
}

第四步:找到函数体里面的函数声明,并将函数体作为值赋给函数名

AO = {
    a:function a() { console.log("a") },
    b:undefined
    d:function (){console.log("d");}
}

预编译就结束了,代码执行的过程中,就一行一行的执行代码就可以啦~ 接着分析下执行过程吧:

// 从上面的AO对象里查找a的值,打印function a() { console.log("a") }
console.log(a);

// 碰到赋值语句,修改AO对象
var a=123;
AO {
    a:123,  
    b:undefined,
    d:function d(){ console.log("b"); },
}

// 函数表达式在预编译处理过了,就跳过
function a() { console.log("a") }

// 从最新的AO对象里找到a的值,打印123
console.log(a);

// 碰到赋值语句,修改AO对象
var b = function(){ console.log("b"); }
AO {
    a:123  
    b:function(){ console.log("b"); }
    d:function d(){ console.log("d"); }
}

// 从AO对象中取到b的值,打印function(){ console.log("b"); }
console.log(b);

// 函数表达式在预编译第四步处理过,就跳过
function d() { console.log("d"); }

明白了吧?在调用函数的同时创建了函数的执行器上下文AO对象,并将形参、变量和函数声明作为该对象的属性,函数声明的值为函数体,变量的值为undefined,形参的值取决于实参。 然后就是执行函数体内的语句。碰到赋值语句就更新AO,遇到函数声明就跳过,遇到打印语句就去当前的AO找值。是不是很容易就搞清楚啦?

下面再吃几个栗子巩固以下吧:

二、例题

例一

function test(a,b){
    console.log(a); //1
    c=0; //AO.c=0
    var c;
    a=3; //AO.a=3
    b=2;//AO.b=2
    console.log(b);//2
    function b(){  console.log("b"); }
    function d(){  console.log("d"); }
    console.log(b);//2
}
test(1);

答案:

1. AO{}
2. 形参和变量名
AO{
    a:undefined,
    b:undefined,
    c:undefined
}
3. 形参实参统一值
AO{
    a:1,
    b:undefined,
    c:undefined
}
3. 找函数声明并赋值
AO{
    a:1,
    b:function b(){  console.log("b"); },
    c:undefined,
    d:function d(){  console.log("d"); }
}

例二

function func(a,b){
    console.log(a,b);// function a(){ console.log("a") }  undefined
    var b = 234;// AO.b=234
    console.log(b);//234
    a=123;//AO.a=123
    console.log(a);//123
    function a(){ console.log("a") }
    var a;
    b=432;//AO.b=432
    var b = function (){ console.log("b") }// AO.b=function (){ console.log("b") }
    console.log(a,b);//123  function (){ console.log("b") }
}
func(1);

答案:

 1. AO{}
 2. AO{
     a:undefined,
     b:undefined
  }
 3. AO{
      a:1,
      b:undefined
  }
 4. AO{
     a:function a(){ console.log("a") },
     b:undefined
 }

全局环境下的预编译

一、规则

  1. GO global object====window
  2. 找变量
  3. 找函数声明,并用函数体赋值

二、例题

例一

console.log(ff); // function ff(ff){....}
function ff(ff){
    console.log(ff);// function ff(){ console.log("ff"); }
    var ff=1234;//AO.ff=1234
    console.log(ff);//1234
    function ff(){ console.log("ff"); }
}
ff(1122);
var ff=2233;

答案:

GO{}
GO{
    ff:undefined
}
GO{
    ff:function ff(ff){
        console.log(ff);
        var ff=1234;
        console.log(ff);
        function ff(){ console.log(ff); }
    }
}

AO{}
AO{
    ff:undefined
}
AO{
    ff:1122
}
AO{
    ff: function ff(){ console.log("ff"); }
}

例二

var glo = 100;//GO.glo=100
function ffn() {
    console.log(glo);
}
ffn();//100

答案:

GO{}
GO{
    glo:undefined,
    ffn:function ffn(){...}
}  
AO{}

例三

global = 100;
function fnn() {
    console.log(global);//undefined
    global = 200;//AO.Global=200
    console.log(global);//200
    var global = 300;
}
fnn();
var global;//声明提升到最前面

答案:

GO{}
GO{
    global:undefined
    fnn:function fnn(){....}
}
AO{}
AO{
    global:undefined
}

例四

function ffnn() {
    console.log(p);//undefined
    if (m) {//undefined
        var p = 100;
    }
    console.log(p);//undefined
    k = 234;//GO.c=234
    console.log(k);//234
}
var m;
ffnn();
m = 10;
console.log(k);//234

答案:

GO{}
GO{
    m:undefined
    ffnn:function ffnn(){...}
}

AO{}
AO{
    p:undefined
}

例五

console.log(bar1());//11
function bar1() {
    foo = 10;//AO.foo=10
    function foo() { console.log("foo") }
    var foo = 11;//AO.foo=11
    return foo;//11
}

答案:

GO{}
GO{
    bar1:function bar1(){...}
}

AO{}
AO{
    foo:undefined
}
AO{
    foo:function foo(){ console.log("foo")}
}

2013百度面试题

function bar() {
    return foo;
    roo = 10;
    function foo() { console.log("foo") }
    var foo = 11;
}
console.log(bar());//foo:function foo(){ console.log("foo")}

答案:

GO{}
GO{
    bar:function bar(){...}
}

AO{}
AO{
    foo:undefined
}
AO{
    foo:function foo(){ console.log("foo")}
}

再来一道巩固题吧,加油

第一题

a = 100;//GO.a=100
function dd(e) {
    function e() { console.log("e"); }
    arguments[0] = 2;//AO.e=2
    console.log(e);//2
    console.log(a);//就近原则--找到AO.a=undefined
    if (a) {//undefined
        var b = 123;
        function c() { console.log("c"); }//现实中:if语句中不允许声明function,所以还是undefined
    }
    var c;
    a = 10;//AO.a=10
    var a;
    console.log(b);//undefined
    f = 123;//GO.f=123
    console.log(c);//undefined
    console.log(a);//10

}
var a;
dd(1)
console.log(a);//GO.A=100
console.log(f);//GO.f=123

答案:

GO{}
GO{
    a:undefined,
    dd:function dd(){...}
}

AO{}
AO{
    e:undefined,
    b:undefined,
    c:undefined,
    a:undefined
}
 AO{
    e:1,
    b:undefined,
    c:undefined,
    a:undefined
}
AO{
    e:function e(){ console.log("e");},
    b:undefined,
    c:undefined  (理想:function c(){console.log("c");}),
    a:undefined
}