预编译的作用
-首先我们要了解,预编译是什么, 就是在函数(JS)执行的前一刻,会创建一个叫做执行期上下文对象,分为AO规则和GO规则
-
(1)AO规则:
-
- 函数在执行前的一瞬间, 生成一个AO对象
2. 看参数, 形参作为AO对象的属性名, 实参作为AO对象的属性值
3. 看变量声明, 变量名为AO对象的属性名, 值为undefined, 如果变量名和形参重名, 不用管
4. 看函数声明, 函数名为AO对象的属性名, 值为函数体, 如果遇到同名( 变量名或者形参名), 直接覆盖( 函数体去覆盖属性值)
- 函数在执行前的一瞬间, 生成一个AO对象
-
(2)GO规则:
-
- 进入script标签, 需要执行代码前的一瞬间, 生成一个GO对象
2. 看变量声明, 变量名为GO对象的属性名, 值为undefined
3. 看函数声明, 函数名为GO对象的属性名, 值为函数体, 如果遇到同名( 变量名), 直接覆盖( 函数体去覆盖属性值)
- 进入script标签, 需要执行代码前的一瞬间, 生成一个GO对象
预编译算法
了解了AO和GO规则之后我们来看一段代码
function fun(a){
console.log(a)
var a = 5;
console.log(a)
}
fun(10)
答案为10和5,显而易见,但是我们需要知道它具体的算法过程
-
预编译阶段AO规则,先看参数
fun.AO={
a:10
}
// 因为形参是属性名,实参是属性值
然后看变量声明:
fun.AO={
a:5
}
//a被赋值为5
最后是函数声明
fun.AO={}
//没有,所以这步省略 -
然后是GO规则运算
console.log(a)
var a = 10;
console.log(a)
function a() {}
console.log(a)
var a = function() {}
console.log(a)
输出结果为下:
可能会很好奇,为什么第一个a的输出会是函数体,我们再来一步一步解析
预编译阶段:
GO = {}
GO = {
a: undefined
}
//变量声明没有,所以是undefined
GO = {
a: function a() {}
}
//函数体覆盖
执行阶段(一行一行的走, 前面没有走完的, 剩下变量的赋值)
GO = {
a: 10
}
GO = {
a: function() {}
}
- 这些都是比较易懂的题目,遇到难的,按照AO和GO得规则去算,一般不会出错,但也有例外,具体有些还是得看代码的运作,比如以下代码:
function fun(){
return foo;
foo = 10;
function foo(){
}
var foo = 11
}
console.log(fun())
面试的时候可能会有一些幌子,这个时候不看清楚你可能就已经开始往下运算了,但是请注意!在函数第一行,出现return就已经不执行下面了,所以运算出来结果就是这个函数体
可是关于预编译的了解,仅仅这些浅短的认知是不够的,有时候还触及到兼容性的问题:
function fun(){
console.log(a); //兼容性问题
if(true){
function a(){}
}
console.log(a)
}
fun()
- 如果碰到if判断,for…除了function作用域之外的都得正常分析,然后上面这段代码,版本不同的浏览器,出来的结果不会相同
所以这个结果,看上去没什么问题,但其实不是绝对的
那么心中还有一个疑问就出来了,什么时候用GO规则,什么时候用AO规则呢,具体请看下图
这么看就一目了然了,函数外是GO,函数内是AO
OK今天的内容结束,希望对你有所帮助,有问题的我去你家辅导