JS编译执行过程,你理解透彻了嘛
前言
每次遇到JavaScript中出乎意料的行为时,我们第一时间会怀疑这门编译语言的优质性,可了解一个人都追求探其本心,而一门编译语言,难道不应该深入了解其内核本质嘛?
前端面试例题引入
这可能是将来你面试,面试官会给你出的一道题目(这个运行结果是什么):
function fn(a) {
console.log(a);
var a = 123
console.log(a);
function a() {}
console.log(a);
var b = function () {} //函数表达式
console.log(b);
function c(){}
var c = a
console.log(c);
}
fn(1);
你先在心里有一个自己的答案,我们接着往下看,结尾附上结果!
JS编译与传统编译的区别
在传统编译语言的流程中,编译是指将高级语言代码转换为低级机器代码的过程,这通常包括三个主要阶段:词法分析、语法分析和代码生成。而在JavaScript等脚本语言中,也有编译的过程,但与传统编译语言有所不同。
- 词法分析(Lexical Analysis) :传统编译语言和JavaScript都需要进行词法分析。在这个阶段,源代码被分割成各种标记,如标识符、关键字、运算符等。这些标记构成了语言的基本元素,在之后的分析过程中被使用。例如,考虑程序var a = 2,这些代码块会被分解成这些词法单元:var、a、=、2、;空格是否被当作词法单元,取决于空格是否在这门语言具有意义。
- 语法分析(Syntax Analysis) :语法分析阶段是编译的核心部分,也称为解析(Parsing)。在这个阶段,编译器将词法分析阶段生成的标记流转换为语法树(Syntax Tree)或抽象语法树(Abstract Syntax Tree,AST)。
- 代码生成(Code Generation) :在传统编译语言中,代码生成阶段将语法树或者中间表示(Intermediate Representation,IR)转换为机器码或者字节码,这样计算机可以直接执行。而在JavaScript中,代码生成阶段将AST转换为可执行的机器码或者字节码的过程通常是由JavaScript引擎中的即时编译器(Just-In-Time Compiler,JIT Compiler)完成的。JIT编译器将JavaScript代码动态地编译为机器代码,以便在运行时执行。
对于只有三步的编译器,JavaScript引擎要复杂得多,它的编译过程不是发生在构建之前的,而是发生在代码执行几微秒,我们称这个过程为预编译。
预编译
代码在执行前需要进行编译操作,用于确定代码之间的各种关联
两个概念
- 函数声明 整体提升
- var 变量 声明提升
两个规则
全局编译 --> 全局执行(函数编译-->函数执行)
V8引擎在全局编译后,在全局执行代码,遇到函数调用,则进行函数编译,然后函数执行。
下面我们通过这个代码运行理解编译过程:
var a = 1
function fn(a) {
var a = 2
function a() { }
console.log(a);
}
fn(3);
- 发生在全局
- 创建GO{}对象
- 找变量声明 将变量名作为GO的属性名,值为underfined
- 在全局找函数声明,将函数名作为GO的属性名,值为该函数体
第一步发生全局编译,根据以上步骤得到:
GO: {
a: underfined
fn: function fn() { }
}
第二步然后全局执行,遇到了函数调用fn(3)
- 发生在函数体内
- 创建一个AO{}对象
- 找形参和变量声明, 将形参和变量名作为AO的属性名,值为underfined
- 形参和实参统一
- 在函数体内找函数声明,将函数名作为AO的属性名,值为该函数体
第三步函数编译,根据以上步骤得到:
- a: underfined
- a: 3
- a: function a(){}
对象里面的键唯一,所以会重复覆盖值
AO:{
a:underfined 3 function a(){}
}
第四步函数编译后,函数执行赋值语句:
- a = 2
所有最后输出结果是:
理解上述编译步骤执行步骤之后,你在思考一下那个面试题,是否有不一样的结果呢?
面试题揭晓结果
如果觉得小编的总结有所帮助得话,请"一键三连"吧,有问题也可以在评论区提出!
关注我,我将输出更多优质内容!
转载自:https://juejin.cn/post/7362029084880011264