首先我们看一段代码
console.log(num) //undefined
var num = '我是num'
console.log(num)
fn()
function fn(){
console.log('我是fn函数')
}
fn()
我们发现函数无论是在上面调用还是下面都是可行的,而num变量在声明之前是undefined,这是为什么呢?这就引出一个预编译的内容
什么是预编译?预编译是是js在代码开始执行之前,对代码进行通读并解释一些内容
预编译有函数预编译-AO,全局预编译-GO
预编译分4个步骤,(先函数预编译再全局也就是先AO再GO)我们通过例子来解读一下
var d = 456
function fn(a,b){
console.log(a);
var c = 123;
console.log(c);
function a(){};//这个是函数声明
console.log(b);
var b = function c(){};//这个是函数表达式
console.log(b);
}
console.log(456)
fn(2,4);
- 创建AO对象(AO是函数执行前形成的自己的一个AO对象,有几个函数就有几个AO对象)上面AO对象就是fn
AO{
}
-
找形参和变量声明,将变量和形参作为AO属性名,值为undefined
解释:从上到下声明的变量依次是a,b,c,分别给它们赋值undefined
注意:预编译只是找声明的变量,并不是赋值,所以把声明的变量都赋为undefined
AO{
a:undefined,
b:undefined,
c:undefined
}
-
将实参值和形参统一
把实参的内容赋给形参,现在是赋值所以a,b有值了
AO{
a:2,
b:4,
c:undefined
}
-
在函数体里面找函数声明,值赋予函数体
之前都是找变量声明,现在才开始找函数声明
注意:是找函数声明不是函数表达式
AO{
a:functin a(){},
b:4,
c:undefined
}
到这里AO的预编译已完成
现在我们看GO,全局预编译(执行顺序和AO一样)
- 创建GO对象(GO对象封装的就是作用域)
- 找形参和变量声明
GO{
d:undefined
}
- 实参和形参统一,没有形参实参所以还是
GO{
d:undefined
}
- 在全局里面找函数声明,值赋予函数体
GO{
d:undefined,
fn:function fn(){}
}
到现在AO和GO都完成了,预编译结束
GO{
d:undefined,
AO{
a:functin a(){},
b:4,
c:undefined
}
}
现在从上到下执行,有赋值的被重新赋值,没有赋值的按照预编译得出结果
最后结果是
d:456
a:function a(){}
c:123
b:4
b:function c(){}
最后我们总结一下
- 创建AO对象(AO是函数执行前形成的自己AO对象)
- 找形参和变量声明,将变量和形参作为AO属性名,值为undefined
- 将实参值和形参统一
- 在函数体里面找函数声明,值赋予函数体
注意:先查AO在看GO,if里面不能声明function