2024年JavaScript之预编译学习(附带多个面试题)_预编译面试题,附面试答案

文末

篇幅有限没有列举更多的前端面试题,小编把整理的前端大厂面试题PDF分享出来,一共有269页

开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】

  1. 词法分析
  2. 语法分析:检查代码是否存在错误,若有错误,引擎会抛出语法错误。同时会构建一颗抽象语法树(AST)。
  3. 预编译
  4. 解释执行

预编译

JavaScript是解释性语言,也就是说,编译一行,执行一行,但js并非上来就进入编译环节,它在编译之前存在预编译过程。

js中预编译一般有两种:全局的预编译和函数的预编译,分别发生在script内代码执行前和函数的执行前。

函数预编译

首先来看一个例子:

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)

就以上述例子中的a为例,有形参a,变量a,函数a,那test函数执行时,此时的a到底是什么呢?

输出结果:

ƒ a() {}
123
123
ƒ () {}

要想弄明白最终的输出结果,就不得不好好学习一下预编译的详细过程。

在预编译学习中,经常听到一句话:函数声明整体提升,变量声明提升

这句话可以解决大多数场景下的预编译问题,但光凭这句话无法理解透预编译,接下来我们来一起捋一下函数预编译的大致流程。

函数预编译四部曲
  1. 预编译开始,会建立AO(Activation Object)对象
  2. 找形参和变量声明,使其作为AO的属性名,值赋予undefined
  3. 实参和形参相统一(将实参值赋值给形参)
  4. 找函数声明,函数名作为AO属性名,值赋予函数体
案例分析

学习了函数的预编译过程,就可以回头细细的品味一下上面的案例:

  1. 先建立AO,并找形参和变量声明
AO :{
    a: undefined,
    b: undefined
}

  1. 形参实参相统一
AO :{
    a: 1,
    b: undefined
}

  1. 找函数声明,值赋予函数体
AO :{
    a: function a() {},
    b: undefined,
    d: function d() {}
}

  1. 预编译过程结束,挨着分析一下console的打印结果:
第一个console.log(a); // 此时AO中a的值为function a() {} 
执行赋值操作:
    a = 123 // AO中的a值修改为123
    第二个console.log(a) // 123
    第三个console.log(a) // 123
    b = function() {} // AO中的b值修改为function b(){}
    console.log(b) // function b(){}

全局预编译

全局中不存在形参和实参,所以只需处理变量声明和函数声明

全局预编译三部曲
  1. 生成GO(Global Object)
  2. 找变量声明,由于全局变量默认挂载在window之上,若window当前已存在当前属性,忽略当前操作,若没有,变量作为属性名,值赋予undefined
  3. 找函数声明,函数类似与变量,先去window上查看,不存在,函数作为函数名,值为函数体
案例分析

将函数预编译案例稍微修改,如下:

// 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);

  1. 生成GO,变量提升,函数提升,得到GO如下:
GO/window: {
    a: undefined,
    test: function() {}
}

  1. 因此第一个a的值为undefined,随后a赋值为1,所以第二个a的值为1

test中定义了变量a,因此打印的a为自身AO中的值。如果test中没有定义a,就会沿着作用域链,当GO中查找a。

注意事项

1. 当函数中出现同样名称的函数名和变量名,编译器真的会先做变量提升再去函数提升吗?查看了一些大佬的博客,当出现变量名和函数名相同时,变量提升应该会被忽略掉,不会做重复的无用之功

2. let/const声明的变量应当同样进行了变量提升,只不过它与var声明的变量做了一定的区分

常见面试题分析

题目一
function test() {
console.log(b);
if (a) {
    var b = 100;
}
console.log(b);
c = 234;
console.log(c);
}
var a;
test();
a = 10;
console.log(c);

  1. 生成GO
GO: {
    a: undefined,
    test: function test() {},
    c: undefined
}

JavaScript中变量如果未经声明就赋值,会默认将变量挂载到window对象上,这也就是所谓的imply global。c就是imply global

  1. test执行,生成test的AO
// AO还会存储[[scope]]属性,存储AO的作用域链

AO: {
    b: undefined,
    [[scope]]: [TestAO, GO]
}

有同学会问,if(a)为false,if内部不会执行,那test的AO中为什么还会有b啊?预编译并不是执行,它只不过把变量、函数等进行提升,只有在执行时,才会设计代码逻辑的判断。

  1. 分析test函数执行
console.log(b) // AO中b为undefined
if (a) // AO中无a,沿[[scope]]找到GO中的a,值为undefined
b = 100; // 不执行
console.log(b) // undefined
c = 234; // AO中没有c属性,沿[[scope]]找到GO中的c修改为234


### 最后

我可以将最近整理的前端面试题分享出来,其中包含**HTML、CSS、JavaScript、服务端与网络、Vue、浏览器、数据结构与算法**等等,还在持续整理更新中,希望大家都能找到心仪的工作。

**[开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】](https://bbs.csdn.net/forums/4304bb5a486d4c3ab8389e65ecb71ac0)**

**篇幅有限,仅展示部分截图:**

![](https://img-blog.csdnimg.cn/img_convert/ff6b8e636a356a01389cd2de0211d347.png)

![](https://img-blog.csdnimg.cn/img_convert/b24f32dd81ead796fa80c27c763d262c.png)

![](https://img-blog.csdnimg.cn/img_convert/c6265dc2681708533916a8d7910506b3.png)

  • 5
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值