注册

【灵魂拷问】当面试官问你JavaScript预编译

(一) 前言


在腾讯字节等其他大厂的面试中,JavaScript预编译是经常会被问到的问题,本文将带大家了解JS预编译中的具体过程


(二)编译执行步骤


传统编译语言编译步骤


对传统编译型语言来说,其编译步骤一般为:词法分析->语法分析->代码生成,下面让我们来分别介绍这3个过程。



  1. 词法分析

这个过程会将代码分隔成一个个语法单元,比如var a = 520;这段代码通常会被分解为vara=520这4个词法单元。



  1. 语法分析

这个过程是将词法单元整合成一个多维数组,即抽象语法树(AST),以下面代码为例


if(typeof a == "undefined" ){ 
a = 0;
} else {
a = a;
}
alert(a);

语法树.jpg


当JavaScript解释器在构造语法树的时候,如果发现无法构造,就会报语法错误(syntaxError),并结束整个代码块的解析。



  1. 代码生成

这个过程是将抽象语法树AST转变为可执行的机器代码,让计算机能读懂执行。


JavaScript编译步骤


比起传统的只有3个步骤的语言的编译器,JavaScript引擎要复杂的多,但总体来看,JavaScript编译过程只有下面三个步骤:
1. 语法分析
2. 预编译
3. 解释执行


(三)预编译详解


预编译概述


JavaScript预编译发生在代码片段执行前的几微秒(甚至更短!),预编译分为两种,一种是函数预编译,另一种是全局预编译,全局预编译发生在页面加载完成时执行,函数预编译发生在函数执行的前一刻。预编译会创建当前环境的执行上下文。


函数的预编译执行四部曲



  1. 创建Activation Object(以下简写为AO对象);
  2. 找形参和变量声明,将变量声明和形参作为AO的属性名,值为underfined;
  3. 将实参和形参值统一;
  4. 在函数体里找函数声明,将函数名作为AO对象的属性名,值赋予函数体。

案例代码


//请问下面的console.log()输出什么?
function fn(a) {
//console.log(a);
var a = 123//变量赋值
//console.log(a);
function a() { }//函数声明
//console.log(a);
var b = function () { }//变量赋值(函数表达式)
//console.log(b);
function d() { }//函数声明
}
fn(1)//函数调用

根据上面的四部曲,对代码注解后,我们可以很轻松的知道四个console.log()输出什么,让我们来看下AO的变化



  1. 创建AO对象

AO{
//空对象
}


  1. 找形参和变量声明,将变量声明和形参作为AO的属性名,值为undefined;

AO{
a: undefined
b: undefined
}


  1. 将实参和形参值统一;

AO{
a: 1,
b: undefined
}


  1. 在函数体里找函数声明,将函数名作为AO对象的属性名,值赋予函数体。

AO{
a: function(){}
b: undefined
d: function(){}
}

最后,下面是完整的预编译过程


AO:{
a:undefined -> 1 -> function a(){}
b:undefined
d:function d(){}
}


全局的预编译执行三部曲



  1. 创建Global Object(以下简写为GO对象);
  2. 找形参和变量声明,将变量声明和形参作为GO的属性名,值为undefined;
  3. 在全局里找函数声明,将函数名作为GO对象的属性名,值赋予函数体。

案例代码


global = 100;
function fn() {
//console.log(global);
global = 200;
//console.log(global);
var global = 300;
}
fn();

根据全局预编译三部曲我们可以知道他的GO变化过程



  1. 创建GO对象

GO{
// 空对象
}


  1. 找形参和变量声明,将变量声明和形参作为GO的属性名,值为underfined

GO: {
global: undefined
}


  1. 在全局里找函数声明,将函数名作为GO对象的属性名,值赋予函数体

GO: {
global: undefined
fn: function() { }
}


注意这里函数声明会带来函数自己的AO,预编译过程继续套用四部曲即可



(四)总结


当遇到面试官问你预编译过程时,可以根据上面的内容轻松解答,同时面试时也会遇到很多问你console.log()输出值的问题,也可以用上面的公式获取正确答案。


作者:橙玉米
链接:https://juejin.cn/post/7030370931478364196

0 个评论

要回复文章请先登录注册