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);
首先来看上面的一道题。
整个执行的顺序,会先创建一个全局对象(GO),首先去找在全局中有无变量的申明,如果有,就先把它的值赋为undefined,然后再去找有无函数申明。这样完成一个预编译的过程。然后在去执行,如中的fn是申明的函数,在预编译阶段已经添加到全局对象中,所以在执行的时候 function fn(a) {..} 会先跳过。然后就执行到 fn(1)的语句。此时要去执行fn的函数,在执行函数的时候,也会先预编译,在函数里的预编译会创建一个AO对象。那么在函数的预编译阶段,会先找到形参和函数里的变量申明,并将值赋为undefined。然后将形参和实参的值统一。之后再找到申明的函数。
就拿上述的例子来说,AO对象的变化过程回事这样的。
//1.找到所有形参和实参的值,并赋为undefined
AO {
a:undefined
b:undefined
}
//2.将形参和实参的值统一
AO {
a:1
b:undefined
}
// 3.找到申明的函数
AO {
a:function a (){}
b:undefined
}
接下来就是一步一步执行函数体内的代码
此时 console.log(a) 在AO对象里a的值为 function a() {},所以输出的为 function () {}.
var a = 123,这句代码,将AO里的a的值改变为123,此时打印a为123.
由于function a() {}在预编译阶段已经完成申明,所以跳过这边。
接下来还是打印a的值,由于a的值为发生改变,所以 打印出来a的值仍是 123.
接下来 var b = function (){},是变量赋值的情形,所以此时AO中的值为 function(){}.
所以打印出b的值为 function(){}.