一、语法分析
浏览器将所有JS检查一遍,看有没有语法错误,这里并不会执行,没有错误则进行第二步,预编译
二、预编译
首先要理解函数声明整体提升,变量 声明提升。
这里要注意变量的提升,一般我们声明一个变量都是
var a = 1; console.log(a) //1 //但实际上拆分成了两步,真正执行是这样的 var a; a = 1; console.log(a) //1
//如果将console.log放a前面会打印出undefined console.log(a) //undefined var a = 1; //因为变量的声明提升了,但是赋值并没有提升,实际上是这样的 var a; console.log(a); a = 1;
1、预编译的时候会创建一个AO对象(Activation Object)执行上下文;
2、找形参和变量声明,将形参和变量作为AO对象的属性名,值为undefined;
3、将形参和实参统一;
4、在函数体里找函数声明,值赋给函数体
举个例子:
function fn(a){ console.log(a); var a = 123; console.log(a); function a(){}; console.log(a); var b = function(){}; console.log(b); function c(); } fu(1);
//打印结果依次对应 function a(){} 123 123 function(){}
function fn(a){ console.log(a); var a = 123; console.log(a); function a(){} console.log(a); var b = function(){} console.log(b) function c(); } fn(1) 预编译的时候创建一个AO对象: 1、预编译的时候会创建一个AO对象(Activation Object)执行上下文; AO={ } 2、找形参和变量声明,将形参和变量作为AO对象的属性名,值为undefined; AO={ a : undefined, b : undefined, } 3、将形参和实参统一 AO={ a : 1, b : undefined //此时b还是undefined,前面已经说了,是变量声明提升,赋值并没有提升 } 4、在函数体里找函数声明,值赋给函数体 AO={ a : function a(){}, //此时a的值已经被覆盖了,因为函数声明整体提升 b : undefined, //b不是函数声明,是函数表达式 c : function c(){} } 最后执行的时候是从AO里面取值 第一个console.log(a) 打印 function a(){} 第二个console.log(a) 因为又重新定义了a,所以打印 123 第三个console.log(a) 和第二个同理,打印 123 第四个console.log(b) 因为把一个函数赋值给了b,所以打印 function (){}
三、语句执行
最后执行的时候是从AO里面取值 第一个console.log(a) 打印 function a(){} 第二个console.log(a) 因为又重新定义了a,所以打印 123 第三个console.log(a) 和第二个同理,打印 123 第四个console.log(b) 因为把一个函数赋值给了b,所以打印 function (){} function fn(a){ /* *这里都是隐式声明 var a,b;这里的变量提升到函数头部,但是赋值不会提升 a = 1;形参赋值 a = function a(){} 因为又有一个函数a,函数声明整体提升 c = function c(){} 因为有一个函数c,函数声明整体提升 然后开始从上往下执行 */ console.log(a); var a = 123; console.log(a); function a(){} console.log(a); var b = function(){} console.log(b); function c(); } fn(1);