8.JavaScript学习笔记——预编译

预编译

文章目录

  • 预编译
    • 1. JavaScript运行三部曲
    • 2. 预编译前奏
    • 3. 预编译过程
      • 3.1 函数预编译四部曲
      • 3.2 全局预编译

1. JavaScript运行三部曲

  • 语法分析:在一行行解释运行之前,程序会先通篇扫描一遍程序有无语法错误;
  • 预编译
  • 解释执行

预编译的效果

1.函数声明整体提升

即程序会将函数声明提到最前面。

test();
function test() {

}

上述程序在C语言中是不被允许的,函数在使用前必须有函数声明。但是,在JavaScript中,由于预编译的存在,上述代码是能够正常运行的。预编译会将函数声明提升到函数执行之前。

即,实际的代码执行顺序是

function test() {

}
test();

2.变量 声明提升

对于变量,不同于函数,其只会将变量的声明提升。

例如:

document.write(a);  //undefined
var a = 123;

若无预编译的作用,在变量声明前使用变量会报错。

由于预编译的作用,实际的代码执行顺序是

var a;
document.write(a);  //undefined
a = 123;

此时,变量的赋值并没有被提升。

2. 预编译前奏

  • imply global(暗示全局变量

对于任何变量,如果有变量未经声明就赋值,此变量就为全局对象(window)所有

例如

a = 123;   //window.a = 123;
console.log(a);  //console.log(window.a);

再例如

function f() {
    var a = b = 1;
}
f();

console.log(window.a);  //a是已声明的局部变量,不归window所有,控制台输出结果为undefined
console.log(window.b);  //b是未经声明的局部变量,且已赋值,为window所有,输出1

连续赋值的顺序是从右往左,先将1赋给b,再将b的值赋给a。这里b属于未经声明的变量。

  • 一切声明的全局变量,全是window的属性
var a = 123;   //window.a = 123;
console.log(a);  //console.log(window.a);

再例如

var a = 123;
var b = 234;
var c = 345;

相当于

window {
    a : 123,
    b : 234,
    c : 345
}

访问全局变量a就相当于在全局对象window中访问a属性。

3. 预编译过程

3.1 函数预编译四部曲

  1. 创建AO(Activation Object),活跃对象(红宝书中的活动对象)
  2. 形参和变量声明,将变量和形参名作为AO属性名,值为undefined
  3. 实参值与形参统一
  4. 在函数体里面找函数声明,值赋予函数体

预编译发生在函数执行的前一时刻

AO是指活跃对象,简单理解为作用域,实际上为执行期上下文

function fn(a) {
    console.log(a);

    var a = 123;

    console.log(a);

    function a() {}

    console.log(a);

    var b = function () {}

    console.log(b);

    function d() {}
}

fn(1);

以以上程序为例说明。

预编译发生在fn(1)执行之前。

预编译:

1.创建AO对象

AO{

}

2.找形参和变量声明,形参名和变量名作为AO对象的属性名,此时属性值为undefined

AO{
    a : undefined,  //此属性以形参a和变量a的名字命名
    b : undefined   //此属性以变量b的名字命名
}

3.将形参和实参相统一

AO{
    a : 1,
    b : undefined
}

4.找函数声明,函数名作为属性名,函数体作为该属性的值

AO{
    a : function a() {},
    b : undefined,
    d : function d() {}
}

预编译后执行函数

function fn(a) {
    console.log(a);    //function a() {}

    var a = 123;       //这里变量声明已经在预编译中执行过,所以函数在执行中此句相当于 a = 123;      
                       //此时AO.a = 123

    console.log(a);    //123

    function a() {}     //此句已在预编译中执行,现在不再执行

    console.log(a);    //123

    var b = function () {}   //此句执行后,AO.b = function () {}

    console.log(b);    //function () {}

    function d() {}
}

fn(1);

3.2 全局预编译

  1. 创建GO(Global Object)对象(红宝书中的变量对象)
  2. 变量声明,将变量名作为GO对象的属性名,值为undefined
  3. 函数声明,将函数名作为GO对象的属性名,值为函数体

GO == window GO就是window

暗示全局变量也归GO所有。

console.log(test);
function test(test) {
    console.log(test);
    var test = 123;
    console.log(test);
    function test() {}
}
test(1);
var test = 234;

1.建立GO对象

GO{

}

2.找变量声明

GO{
    test : undefined
}

3.找函数声明

GO{
    test : funcion test(test) {
        console.log(test);
        var test = 123;
        console.log(test);
        function test() {}
    }
}

4.执行第一句(console.log(test);

5.函数声明在全局预编译中已执行,跳到test(1),在执行函数前,进行函数预编译

6.建立AO对象

AO{

}

7.找形参和变量声明

AO{
    test : undefined
}

8.形参与实参统一

AO{
    test : 1
}

9.找函数声明

AO{
    test : function test() {}
}

10.执行函数

……

你可能感兴趣的:(javascript,学习,前端)