在讲预编译执行,我们需要先了解js执行的一个过程,也就是js运行三部曲,首先,我们知道,javascript是单线程的解释性语言,单线程就是先执行完一个,再执行另一个,解释性语言就是先翻译一行,再执行一行,先翻译一行,再执行一行,但是js在执行之前通常会先通篇扫描一遍代码,而不执行代码,通篇扫描就是看看代码有没有什么低级语法错误,这个过程(通篇扫描)就叫语法(义)分析,而在通篇扫描完成之后,才真正开始预编译过程,最后才开始解释一行,执行一行,解释一行,执行一行
第二个知识点
1、如果一个变量未经声明就附值,并不会报错,而是被提升到全局对象window中
a =10;
console.log(a);//10
console.log(window.a);//10
2、全局上声明的任何变量(全局变量),即使声明了,也全是window的属性,意思就是在全局环境下访问的a就相当于访问window.a,只不过window 被默认忽略了而已
var a=10;
===
window {
a:123
}
console.log(a);//10
console.log(window.a);//10
预编译四部曲(函数内的预编译)
例子
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(){}
}
fn(1)
注意;相同变量名会覆盖之前声明的值
预编译就是把函数参数,变量声明,函数声明提升到逻辑的最前面,发生在函数执行的前一刻
首先
第一步
创建AO(activative object)对象——也叫执行期上下文
AO{
}
第二步
找形参和变量声明,将变量和形参名作为AO属性名,值为undefined
AO{
a :undefined
b :undefined
}
第三步
将形参值和实参相统一
AO{
a :1
b :undefined
}
将实参的值赋予形参(a的undefind值被覆盖为1)
第四部
在函数体里面找函数声明,值赋予函数体
AO{
a :function a(){}
b :undefined
d:function d(){}
}
AO对象创建完后,开始执行上面函数
function fn (a){
console.log(a); // :function a(){}
var a =123;
console.log(a); //123
function a(){}
console.log(a); //123
var b =function(){}
console.log(b); //:function (){}
function d(){}
}
fn(1)
解释:
在AO对象创建完毕后,我们开始执行函数,首先打印第一个console.log(a),在AO里面寻找,为function a(){},然后执行第二行,由于a在执行之前变量 声明已经被提升,此时的var a=123相当于 a=123; a此时的值把AO里面的function a(){}覆盖,变成 a:123,然后执行第三行打印a,值为123,第四行函数声明在AO执行的第四步骤已被提升,执行第五行console.log(a),依然为123,第6行的函数表达式var b = function(){}就相当于变量提升,var b;被提升,剩 function (){},因此第七行,打印出function(){},此时的b的值为function(){},最后一行函数声明也在AO执行的第四步骤被提升了
函数声明是整体 提升
变量 声明提升(变量声明就是 var a =10,其中的 var a;就是变量声明,var a=10;表示变量声明+变量附值 )变量 声明提升就相当于把var a=10;拆分成var a ; 跟a =10,然后把var a;提升到逻辑的最前面
函数表达式也是变量 声明提升
比如:
function test(){
}
test();
表示在全局变量下定义一个函数test(),并用test()调用它