js基础篇(2)— js 运行流程,语法解析、预编译具体流程

211 阅读2分钟

我们知道JavaScript是一种解释性语言,那它运行的三大部分为:

1. 语法解析阶段:

①词法分析:将js代码分割为有意义的代码块,这些代码块我们可以称之为 "词法单元"。

②语法分析:将词法单元流转换成一棵抽象语法树(AST 抽象语法树)。

③转换:对生成的AST树节点进行处理(例如:如果使用ES6编写代码,将let、const转换成var),并且系统会把整篇代码扫描一下,看看有没有低级语法错误。

④代码生成:根据上面生成的AST树来生成对应代码。

2. 预编译阶段:

①全局作用域的预编译:

Ⅰ. 创建 GO 对象
Ⅱ. 找变量声明,将变量名作为GO对象的属性名,值为undefined
Ⅲ. 找函数声明,值赋予函数体

②函数作用域的预编译:

Ⅰ. 创建 AO 对象
Ⅱ. 找形参和变量声明,并作为AO对象的属性名,值为undefined
Ⅲ. 将是实参和形参相统一(将实参的值,赋给形参)
Ⅳ. 找函数声明,会覆盖变量声明

3. 执行代码

预编译例题:

function fn(a,c) {
    console.log(a) // function a() { }
    var a = 123
    console.log(a) // 123
    console.log(c) // function c() { }
    function a() { }
    if(false) {
        var d = 456
    }
    console.log(d) // undefined
    console.log(b) // undefined
    var b = function () { }
    console.log(b) // function () { }
    function c() { }
    console.log(c) // function c() { }
}

fn(1,2)

上述代码函数预编译具体流程:

1. 创建AO对象
AO { }
2. 找形参和变量声明,并作为AO对象的属性名,值为undefined
AO {
    a: undefined,
    c: undefined,
    d: undefined,
    b: undefined
}
3. 将是实参和形参相统一(将实参的值,赋给形参)
AO {
    a: 1,
    c: 2,
    d: undefined,
    b: undefined
}
4. 找函数声明,并覆盖变量声明
AO {
    a: function a() { },
    c: function c() { },
    d: undefined,
    b: undefined
}

由上可以,执行前AO对象为4中的值,故执行结果如下:

function fn(a,c) {
    console.log(a) // 此时 a 为 function a() { }  
    var a = 123
    console.log(a) // 此时 给 a 赋值123 覆盖了原值 function a() { }
    console.log(c) // 此时 c 为 function c() { }
    function a() { }
    if(false) {
        var d = 456 // 不执行
    }
    console.log(d) // 此时 d 为 undefined
    console.log(b) // 此时 b 为 undefined
    var b = function () { }
    console.log(b) // 此时给 b 赋值 function () { } 覆盖了原值 undefined
    function c() { }
    console.log(c) // 此时 c 仍为 function c() { }
}

fn(1,2)