JavaScript 知识点整理
1. 什么是AST?它在前端有哪些应用场景?
AST Abstract Syntax Tree抽象语法树,用于表达源码的树形结构
应用:
- Babel:一个广泛使用的 JS 编译器,将ES6+ 或 JSX 等现代语法转换为兼容性较好的 ES5 代码。
- Eslint:JS 静态代码分析工具,它基于 AST 来分析代码中潜在问题和违反的代码规范。
- Terser:JS 压缩工具,使用 AST 进行代码压缩和混淆
- webpack 和 Rollup:构建工具使用AST 来优化 JS 和其他前端资源的打包过程。
AST 是前端开发中处理代码、优化构建、提高代码质量和实现跨语言支持的核心工具之一。它帮助前端工具深入理解代码结构,从而对代码进行高效的转化、优化和分析。通过AST,前端开发者能够更加轻松地进行代码转换、静态检查、压缩和混淆等操作,从而提高效率和应用性能。
2.中序遍历、前序遍历、后续遍历
前序遍历:根左右 ABDECFG
中序遍历: 左根右 DBEAFCG
后序遍历:左右根 DEBFGCA
3.什么是 BFF,它又有什么用?
BFF (Backend For Frontend)是一种架构模式,专门为前端应用提供定制化的后端服务。它的核心思想是为不同的前端客户端(如web、移动端、桌面端等)提供专门的后端服务,而不是让所有的客户端共享一个通用后端API
用途:
1)优化前端性能:
- 减少请求次数:BFF 可以将多个后端API的请求合并为一个,减少前端请求的次数。
- 减少数据传输量:BFF 可以根据前端的需求,对后端返回的数据进行聚合、过滤或转换、减少不必要的数据传输。
2)解耦前端和后端 - 独立开发
- 灵活适配:BFF可以根据不同的客户端(web、移动端)提供不同的API,而不需要修改后端服务
3)统一安全控制
在 BFF 层集中处理身份验证、权限管理、请求限流等安全策略,避免分散到各个微服务。
4)缓存与容错:缓存高频访问数据(如用户信息),减少后端压力。实现重试、熔断等机制。增强系统容错性
4.同一个url地址,如何实现手机打开是移动端页面,电脑打开是web页面
- 流体布局: 100% 、相对单位rem、 flex、grid
- 媒介查询(media query):一套代码
css 判断(@media),js逻辑(matchMedia)
存在问题: 1.差异化越大,开发维护成本越大;2.打包体积(PC + Mobile)
结论:适合差异化较小的站点 - 服务器判断请求头:user-agent :独立开发、分开开发、独立部署
5.当 QPS 达到峰值是,该如何处理?
- 缓存:本地缓存、服务器缓存、CDN 预热…
- 减少请求:合并请求、雪碧图…
- 延时请求: 懒加载…
- 扩容
- 数据库优化:sql优化、索引、读写分离
- 负载均衡
- 监控报警
6 如何实现精确的setInterval?
1.根据 performance.now 动态补偿
2.优先使用 requestAnimationFrame 替代定时器,与屏幕刷新率同步(约 16.67ms/帧)【不受失活页面影响,受很多其他因素影响】
3.webworker 【不受失活页面影响,不受渲染帧的影响】
7.页面上有100万个任务需要执行,如何保证页面不卡顿
- 任务分批处理: requestAnimationFrame 或者 setTimeout 实现异步调度
- requestIdleCallback:在浏览器空闲时执行低优先级任务;
- Web Workers:将计算密集型任务移到其他线程:【缺陷:1.无法直接操作 DOM;2.线程间通信(postMessage)有性能开销,需减少数据传递频率】
8.死循环会导致什么后果?无限递归会导致什么后果?
死循环:页面卡顿、无响应
无线递归: 堆栈溢出、程序崩溃
9.后端响应巨量数据,前端如何避免其性能问题?
减少主线程负载,分而治之。优先通过流式传输、分页、Worker多线程减轻数据压力,再结合虚拟化、Canvas等渲染优化提升用户体验。
- 网络性能:
1. 改接口规格
2. sse( server sent event ) / websocket 实时推送
3. 流式读取: etch stream
const resp = await fetch("XXXX");//等待响应头到达
const body = await resp.json();//等待响应体
- 渲染性能:
- 分页(产品参与协调)
- 分片渲染 (React Fiber)
- 虚拟滚动
- canvas
10.vue 项目有哪些常见的优化手段?
-
图片懒加载、路由懒加载
-
suspence 【用于管理异步操作(如数据加载、代码分割)的组件】
-
v-if 和 v-show
-
打包手段优化
-
网络手段优化
- CDN (公共库)
- http2
- 图片格式优化
- gzip
- 请求合并
- GraphQL
-
key
-
computed
-
保持对象地址的稳定性
-
延迟装载
-
v-model lazy 延时双向绑定
-
冻结对象(vue2)
-
函数式组件(vue2)
11. isNaN 和 Number.NaN 的函数区别?
isNaN 和 Number.isNaN 是 JavaScript 中用于判断 NaN (Not-a-number)的函数。
isNaN 接收参数后,会尝试将这个参数转换为数值,任何不能被转换为数值的值都会返回 true,isNaN(‘true’) === true;
Number.isNaN 会首先判断传入的参数是否是数字,如果是数字再继续判断是否 NaN。
12. Map和object的区别?
Map | Object | |
---|---|---|
构造方式 | new Map()创建 | 通过字面量、new Object()、Object.create()等方式创建 |
键的类型 | Map的键可以是任意类型,包括对象、数组、函数等 | 只能是字符串或者Symbol,其他类型的键会被转换为字符串 |
键的顺序 | 有序 | 无序 |
键值大小 | 使用 .size 属性来获取其大小。使用 .get() 方法获取值。 | 没有内置的方法来获取其大小(键值对的数量)采用Object.keys(xxx).length获取大小。使用 . 获取值。 |
原型继承 | 不会从原型链中继承属性 | 会从原型链中继承属性 |
迭代 | 可以直接迭代 | 获取到键值后才能迭代 |
性能 | 在频繁添加和删除键值对性能更好 | 在频繁添加和删除键值对未作出优化 |
13. map和weakMap的区别?
Map | weakMap | |
---|---|---|
键的类型 | 可以使用任何类型的值作为键,包括原始类型(如字符串、数字)和对象。 | 只能使用对象作为键 |
垃圾回收机制 | 键是 强引用。即使键对象已无其他引用,只要 Map 存在,该对象仍不会被垃圾回收,可能导致内存泄漏。 | 键是 弱引用。当键对象无其他引用时,垃圾回收机制会自动回收该键及其关联的值,避免内存泄漏。 |
迭代和操作 | 支持 遍历操作(如 forEach、for…of),可通过 keys()、values()、entries() 获取迭代器。内置 size 属性,可获取键值对数量。 | 不支持遍历,无 size 属性,也无法直接获取所有键值对。设计初衷是保护键对象的隐私和自动清理,因此不暴露遍历接口。 |
14. JavaScript 标准内置对象
- 基本对象
构成 JavaScript 的核心基础,用于定义其他对象或行为:
- Object:所有对象的基类,提供属性操作(如 hasOwnProperty())
- Function:函数的构造器,每个函数都是其实例
- Boolean 和 Symbol:分别表示布尔值和唯一符号的包装器
- 处理特定类型的数据:
- String:字符串操作(如 charAt()、replace())
- Number 和 BigInt:数值类型,后者支持大整数运算
- Boolean:布尔值的包装类型(注意与基本类型的 true/false 区分)
- 集合与数据结构
存储和管理数据集合:
- Array:有序元素集合,支持动态操作(如 push()、map())
- Map 和 Set:键值对集合与唯一值集合
- WeakMap:弱引用键值对,避免内存泄漏
- 错误处理对象
捕获和管理运行时错误:
- Error:基础错误类型
- 子类:TypeError(类型错误)、SyntaxError(语法错误)、ReferenceError(引用错误)等 3 5。
- 数学与日期对象
处理数学运算和日期时间:
- Math:提供数学函数(如 Math.random())和常量(如 Math.PI)
- Date:解析和计算日期时间(如 getFullYear())
- 其他功能对象
扩展语言能力的关键对象:
- JSON:数据序列化与解析(JSON.stringify()、JSON.parse())
- RegExp:正则表达式,用于字符串模式匹配
- Promise:管理异步操作
- Proxy:对象代理,支持元编程(如拦截对象操作)
- 全局属性与函数
全局作用域下的属性和工具函数:
- 值属性:Infinity(无穷大)、NaN(非数字)、undefined
- 全局函数:eval()(执行字符串代码)、parseInt()(字符串转整数)、isNaN()(判断非数字)
15.数组有哪些原生方法
- 数组和字符串的转换方法:toString()、toLocalString()、join() 其中 join() 方法可以指定转换为字符串时的分隔符。
- 数组尾部操作的方法 pop() 和 push(),push 方法可以传入多个参数。
- 数组首部操作的方法 shift() 和 unshift() 重排序的方法 reverse() 和 sort(),sort() 方法可以传入一个函数来进行比较,传入前后两个值,如果返回值为正数,则交换两个参数的位置。
- 数组插入方法 splice(),影响原数组查找特定项的索引的方法,indexOf() 和 lastIndexOf() 迭代方法 every()、some()、filter()、map() 和 forEach() 方法
- 数组归并方法 reduce() 和 reduceRight() 方法,不影响原数组
- 数组连接的方法 concat() ,返回的是拼接好的数组,不影响原数组。
- 数组截取办法 slice(),用于截取数组中的一部分返回,不影响原数组。
16.Unicode、UTF-8、UTF-16、UTF-32的区别?
17.escape、encodeURI、encodeURIComponent的区别
方法 | 编码对象 | 编码范围 | 编码规则 | 兼容性 |
---|---|---|---|---|
escape | 字符串 | 除 ASCII字母、数字、@*/+ 外的字符均编码为 %XX 或 %uXXXX(Unicode编码) | 直接对字符的Unicode编码加 %u 前缀,仅支持ASCII字符(≤255),已过时且不推荐使用 | 不适用于URL,仅旧环境兼容 |
encodeURI | 完整URL | 保留URL合法字符(如 😕?#[]@ 等),仅编码空格、中文等非法字符为 %XX | 将非法字符转换为UTF-8字节后编码,保持URL结构完整 | 适用于编码整个URL |
encodeURIComponent | URL组成部分(如参数) | 编码范围更广,包括 😕?# 等保留字符,仅保留 !*()’ 和基本ASCII字符 | 对字符进行更严格编码,确保参数值安全传输,常用于拼接查询字符串 | 适用于URL参数或路径片段 |
18. JavaScript为什么要进行变量提升,它导致了什么问题?
变量提升是JavaScript早期设计中的权衡产物,虽然提升了性能和容错性,但也带来了作用域混乱、变量污染等问题。现代开发中,应优先使用let/const,并通过规范代码结构规避潜在风险
19. ESM 和 CommonJS 有什么区别?
ESM | CMJ | |
---|---|---|
标准来源 | 官方标准(新增语法) | 社区标准(新增API) |
导入机制 | 静态声明依赖,模块关系在编译时确定,支持 Tree Shaking 优化 | 动态加载,模块运行时动态生成,灵活性高 |
加载机制 | 编译时静态分析依赖,支持异步加载 | 运行时同步加载,阻塞后续代码执行 |
动态加载 | 支持 import 动态导入(返回 Promise) | 直接使用 require()动态加载 |
作用域 | 块级作用域,严格模式(this 为 undefined) | 共享全局作用域,可能污染变量 |
20.use strict 是什么意思 ? 使用它区别是什么?
是 JavaScript 中用于启用**严格模式(Strict Mode)**的指令,由 ECMAScript 5(ES5)引入。其核心目的是通过更严格的语法和运行时检查,减少代码中的潜在错误,提升安全性及性能。
区别:
- 构造函数必须使用 new;
- 变量必须声明
- 禁止使用eval、 with 语句;
- 禁止 this 关键字指向全局对象;
- 对象不能有重名的属性;
优势: - 消除静默错误:将隐式错误转为显式报错,提升代码健壮性
- 提高安全性:限制危险操作(如 eval、with),减少漏洞风险
- 优化性能:静态分析支持编译器优化(如 Tree Shaking)
21.for…in和for…of的区别
for…in | for…of | |
---|---|---|
迭代对象 | 遍历对象的可枚举属性(包括继承的属性),适用于普通对象、数组(但不推荐) | 遍历可迭代对象(如数组、字符串、Map、Set等),要求对象实现 Symbol.interator接口 |
迭代内容 | 返回键名 | 返回值 |
遍历顺序 | 不确定(对象属性无固定顺序) | 确定(按可迭代对象的顺序,如数组索引顺序) |
兼容性 | – | ES6+ |
性能 | 会检查原型链,性能较低 | 对数组的遍历效率接近 传统 for 循环 |