js预编译是前端平时面试笔试题的必考题,预编译能够很大程度的考察面试者的js基础,所以也是现如今各大公司的热门考点。
面对这种考点时,有些人总喜欢刷题,想通过题海战术来解决问题。但是这种做法是非常费时间的,只有掌握了真正的方法,才能事半功倍。
那么什么是预编译呢?其实预编译就是js代码执行过程中的一个阶段,那么js代码执行的过程是怎么样的呢?
js代码执行步骤主要有三个阶段:
- 首先是检查代码通篇的语法错误
- 其次就是js的预编译过程了
- 最后就是代码的实际执行过程(解释一行,执行一行)
下面简单的看一段代码(预热一下):
(a) test() function test() { console.log(1) // 1 } (b) console.log(a); // undefined var a ; 函数申明整体提升,变量只有申明提升,赋值不提升 (c) console.log(a) // function a(a){} function a(a){} var a = 1 (d) var a = 1 b = 2 console.log(window.b) // a = window.a // b = window.b
上面一共列出了四个例子,每个例子针对不同的情况:
- (a)主要考察了函数整体提升;
- (b)主要考察了变量申明提升;
- (c)把a和b融合在一起了,进行联合考察;
- (d)就比较常见了,全局变量挂载window。
上面这几种情况是非常简单的题型,如果没有解题方法,遇到这种题应该还能够解决,一旦遇到比较复杂的题就得碰运气了。
类似如下:
(a) function test(){ var a = b = 1 // 1.先声明 var a // 2.1赋值给b // 3.b的值赋值给a } console.log(a) // error console.log(window.a) // undefined console.log(b) // 1 console.log(window.b) // 1 (b) function test(a) { console.log(a) // function a() {} var a = 1 console.log(a) // 1 function a() {} console.log(a) // 1 var b = function () {} console.log(b) // function(){} function d() {} } test(2)
这两道题就比刚才的题复杂多了,但是如果没有解题方法,还是很难全部做对的。答案已经给出来了,可以先对照着看一下,看自己能做对多少。
解题方法来了(敲黑板),预编译根据作用域划分,主要有两种环境,第一种是函数预编预,另外一种就是全局上下文了。那么这两种情况应该怎么办呢?
函数预编译:AO activation object (活跃对象,函数上下文)
function test(a) { console.log(a) // function a() {} var a = 1 console.log(a) // 1 function a() {} console.log(a) // 1 var b = function () {} console.log(b) // function(){} function d() {} } test(2) 执行过程 AO = { } 第一步:寻找形参和变量申明 AO = { a: undefined, b: undefined } 第二步:实参赋值给形参 AO = { a: undefined -> 2, b: undefined } 第三步:寻找函数体的申明,并赋值 AO = { a: undefined -> 2 -> function a() {}, b: undefined, d: function d() {} } 第四步:执行函数体第一句 // console.log(a):function a(){} 第五步:执行函数体第二局 //a = 1 AO = { a: undefined -> 2 -> function a() {} -> 1, b: undefined, d: function d() {} } ....
以上流程图可以清晰的看明白整个解题的思路,遇到函数域的预编译题时就可以按照这个步骤去解题,百试不爽。
全局预编译:GO global object 全局上下文
(a) var a = 1 function a() { console.log(2) } console.log(a) // 1 GO = { a: undefined -> function a(){} -> 1 } 其实GO就是window,即GO === window (b) console.log(a, b) // function a(){} undefined function a() {} var b = function () {} GO = { b: undefined a: function a(){} }
全局编译其实类似函数域编译,只是多了一个global,一般的题型中,全局上下文和函数域的预编译都是联合在一起考察。但是总的思路就是:
- 找变量
- 找函数申明
- 执行
掌握了这个思路,遇到预编译的题就再也不怕了,希望分享的能够帮助到大家,如果大家有不同的见解,可以留言探讨。