我们知道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)