js函数预编译
预编译是js的一个基础知识,也是如今面试的常见考点,今天我们来一次搞懂,不留遗憾。
函数预编译过程
我们将函数预编的过程分成以下四步进行理解。
- 创建一个AO对象
AO{}
- 找形参和变量声明 将变量和形参名作为AO对象的属性名 值为
undefined
- 将实参和形参相统一
- 在函数体里面找函数声明 值赋予函数体
举个例子,我们先看看局部的预编译,观察以下代码,思考所有的console.log将打印什么值?
1 function fn(a){
2 console.log(a);
3 var a = 123;
4 console.log(a);
5 function a(){};
6 console.log(a);
7 console.log(b);
8 var b = function(){}
9 console.log(b);
10 function c(){}
11 console.log(c);
12 }
13
14 fn(1)
有没有感到一脸懵逼?
接下来,我们来分析一下上述代码的预编译过程,
注:为了方便小伙伴们看清楚预编译的四步,「」中的数字将表示上述代码所对应的行数。
// 第一步:创建一个AO对象 AO{}
AO{
// 第二步:找形参和变量声明 将变量和形参名作为AO对象的属性名 值为`undefined`
a:「形参1」「变量声明3」undefined
b:「变量声明8」 undefined
// 第三步: 将实参和形参相统一
a:「形参1」「变量声明3」undefined
「实参14」 1
b:「变量声明8」 undefined
// 第四步:在函数体里面找函数声明 值赋予函数体
a:「形参1」「变量声明3」undefined
「实参14」 1
「函数声明5」 function a(){}
b:「变量声明8」 undefined
c:「函数声明10」 function c(){}
}
js为解释形语言,一行一行执行,我们来看一下执行的结果
1 function fn(a){
2 console.log(a); // function a(){}
3 var a = 123;
4 console.log(a); // 123
5 function a(){}; // 不会产生代码执行
6 console.log(a); // 123
7 console.log(b); // undefined
8 var b = function(){}
9 console.log(b); // function(){}
10 function c(){}
11 console.log(c); // function c(){}
12 }
13
14 fn(1)
好了,搞懂了局部的函数预编译,接下来,我们看看全局的预编译。
全局的预编译
- 创建一个Go对象
- 找变量声明 将变量名作为GO对象的属性名 值为 undefined
- 在全局里面找函数声明 值赋予函数体
GO{
test : undefined「20」 function test(){}「3」
b:undefined
}
1 console.log(test); // function test(){}
2 console.log(b); // undefined
3 function test(a){
4 // AO{
5 // a:undefined, 234
6 // c:undefined,
7 // }
8 console.log(c); // undefined
9 var a = b = 345; // 全局里面把b重新赋值 b = 345
10 c = 9
11 if(false){ // 不进来
12 var c = 789
13 }
14 console.log(a); // 345
15 console.log(c); // 9
16 }
17 test(234)
18 console.log(b); // 345
19 console.log(test); // function test(){}
20 var test = 123
21 var b = 456