JavaScript(以下简称js)的一个特点是逐行执行,而js代码在执行前还有两个步骤:
1.语法分析:代码执行前,引擎会检查你的代码是否有低级的语法错误
2.预编译:本篇重点
3.解释执行:根据已编译好的代码来逐行执行
理解预编译之前,先了解一下变量声明和函数声明这两个概念:
1.变量声明 var
2.函数声明 function
var a = 1; // 变量声明(赋值)
function a(){ //函数声明
}
var a = function (){ // 注意,此处是变量声明,将函数赋值给a
}
预编译的过程
每一个函数都有自己的执行上下文EC(执行环境 execution context),并且每个执行上下文中都有它自己的变量对象,用于存储执行上下文中的变量 、函数声明 、函数参数,这解释了js如何找到我们定义的函数和变量
1.函数运行前的一瞬间,会生成一个AO对象(Active Object)
2.分析参数,形参作为AO对象的属性名,实参作为AO对象的属性值
3.分析变量声明,变量名为属性名,值为undefined,如果遇到同名,则不做任何改变
4.分析函数声明,函数名为属性名,值为函数体,如果遇到同名,直接覆盖
函数执行每一次,就会产生一次预编译的过程,预编译发生在执行前
实例练习
1.
function t(greet){
console.log(greet); //function greet(){console.log('hello world')}
function greet(){
console.log('hello world');
}
console.log(greet) //function greet(){console.log('hello world')}
}
t(5);
预编译过程:
1.生成AO
t.AO = {}
2.分析参数
t.AO = {
greet : 5
}
3.分析变量声明
没有,略过
4.分析函数声明
t.AO = {
greet:function greet(){
console.log('hello world');
//遇到同名直接覆盖,所以greet的值为函数体,而不是5了
}
}
预编译结束,逐行执行代码
2.
function t(greet){
console.log(greet); //5
var greet = function (){
console.log('hello world');
}
console.log(greet) //function (){console.log('hello world')}
}
t(5);
预编译过程:
1.生成AO
t.AO = {}
2.分析参数
t.AO = {
greet : 5
}
3.分析var
t.AO = {
greet : 5 //变量声明遇到同名不作任何改变,所以依然是5
}
4.分析函数声明
没有,略过
预编译结束
执行环节:
逐行执行,产生赋值
t.AO = {
greet : function (){
console.log('hello world');
}
}
注意:预编译阶段发生变量声明和函数声明,没有初始化行为(赋值)时,匿名函数不参与预编译
只有在解释执行阶段才会进行变量初始化