function test(a) {
console.log(a);
var a = 123;
console.log(a);
function a() {}
console.log(a);
var b = function() {}
console.log(b);
function d() {}
}
test(1)
// test部分的结果与函数部分相同,再次只分析全局部分
console.log(a);
var a = 1;
console.log(a);
function test(a) {
console.log(a);
var a = 123;
console.log(a);
function a() {}
console.log(a);
console.log(b);
var b = function() {}
console.log(b);
}
test(2);
预编译
在学习
JavaScript
预编译之前,先了解一下JavaScript
从编译到执行的过程,大致可分为四步:AST
)。预编译
js
中预编译一般有两种:全局的预编译和函数的预编译,分别发生在script
内代码执行前和函数的执行前。函数预编译
首先来看一个例子:
就以上述例子中的
a
为例,有形参a
,变量a
,函数a
,那test
函数执行时,此时的a
到底是什么呢?输出结果:
要想弄明白最终的输出结果,就不得不好好学习一下预编译的详细过程。
在预编译学习中,经常听到一句话:函数声明整体提升,变量声明提升。
这句话可以解决大多数场景下的预编译面试题,但光凭这句话无法吃透预编译的,因此接下来我们来一起捋一下函数预编译的详细流程。
函数预编译四部曲
AO(Activation Object)
对象AO
的属性名,值赋予undefined
AO
属性名,值赋予函数体案例分析
学习了函数的预编译过程,就可以回头细细的品味一下上面的案例:
AO
,并找形参和变量声明,值赋予undefined
console
的打印结果:全局预编译
全局中不存在形参和实参,所以全局预编译只需处理变量声明和函数声明。
全局预编译三部曲
GO(Global Object)
window
之上,若window
当前已存在当前属性,忽略当前操作,若没有,变量作为属性名,值赋予undefined
。window
上查看,不存在,函数作为函数名,值为函数体案例分析
将函数预编译案例稍微修改,如下:
GO
,变量提升,函数提升,得到GO
如下:a
的值为undefined
,随后a
赋值为1
,所以第二个a
的值为1
注意事项
1. 当函数中出现同样名称的函数名和变量名,编译器真的会先做变量提升再去函数提升吗?这个问题暂时无法验证,如果有大佬知道,希望可以评论告诉一下,谢谢
2. let/const声明的变量应当同样进行了变量提升,只不过它与var声明的变量做了一定的区分
常见面试题分析
题目一
GO
test
执行,生成test
的AO
test
函数执行题目二
答案
题目三
return; 与上面案例的if一样,预编译环节不会处理
答案
题目四
答案
题目五
答案
1
总结
预编译的题目多数情况下就可以采用以下原则:
如果遇到复杂的情况,就要按照全局预编译的三部曲和函数预编译的四部曲一步一步推导。
最后,在预编译时一定要注意:
return、if
等代码逻辑判断是在执行时候做的,预编译不管这些,预编译只管变量、形参、函数等。Sent from PPHub