JS三部曲
1.语法分析(扫描)
2.预编译
3.解释执行
预编译不仅仅会发生在代码块执行之前(全局的预编译),它更多的是会发生在函数执行之前。
全局的预编译
1.首先创建一个Go对象(Global Object)
2.浏览寻找全局变量将其作为Go的属性名并赋值undefined
3.寻找函数名并赋值函数体
举个简单的例子
var a = 123;
function a() {}
console.log(a);
a.全局预编译的过程,首先应该先创建一个Go对象
Go{ }
b.寻找全局变量名赋值undefined
Go{
a:undefined
}
c.寻找函数名并赋值函数体,这时候Go对象中的a变量的值,就会被覆盖
Go{
a:function() {}
}
执行完以上内容,预编译就完成了,此时a变量的值是一个函数,接下来开始执行程序,a被赋值123覆盖以前的值,所以输出的值为123.
预编译不仅会发生在全局还会发生在函数执行前的一刻
过程与全局预编译类似
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() {}
}
答案:
funciton a() {}
123
123
function () {}
a.根据预编译的过程首先创建一个Ao对象
Ao()
b.找形参和变量声明
Ao{
a:undefined (首先找到的形参a,然后变量a覆盖形参a,并赋值undefined)
b: undefined (这里注意b是一个变量名,而不是形参)
}
c.形实参统一
d.寻找函数声明并赋值
Ao{
a: function () {}
b:undefined
d:function() {}
}
预编译结束开始执行,执行第一个console.log ,a的值为function a() {},然后给a赋值123,覆盖以前的值,所以第二个console.log为123,第三个依然为123,因为中间的函数在预编译的过程中已经执行过了,然后b赋值函数体,所以最后b输出的是一个函数
*总结一句话:函数声明整体提升,变量的声明提升