【前端面试4】框架以及TS

文章目录

  • 前言
    • [1. 什么是 AST(抽象语法树)?](#1. 什么是 AST(抽象语法树)?)
    • [2.Vue 的 SFC 是什么?如何最大化利用?](#2.Vue 的 SFC 是什么?如何最大化利用?)
    • [3. SSR 是什么?如何使用?](#3. SSR 是什么?如何使用?)
    • [4. Vue2 为什么无法监听数组变化,该如何做?](#4. Vue2 为什么无法监听数组变化,该如何做?)
    • [5.keep-alive 是什么?react 如何实现类似功能?](#5.keep-alive 是什么?react 如何实现类似功能?)
    • [6. 什么时候用计算属性,什么时候用监听?](#6. 什么时候用计算属性,什么时候用监听?)
    • [7. JS 中生成器和迭代器是什么,实际有什么应用?](#7. JS 中生成器和迭代器是什么,实际有什么应用?)
    • [8. 什么是 TS 的 infer?如何使用?](#8. 什么是 TS 的 infer?如何使用?)
    • 9.简要描述vite的原理
    • [10. 简要说明如何最大支持 Tree Shaking?](#10. 简要说明如何最大支持 Tree Shaking?)
    • 11.用math.random来计算抽奖概率会有什么问题?

前言

大家好,今天是冲击中级工程师第四天,让我们来完成今天的面试题打卡。

1. 什么是 AST(抽象语法树)?

答案:编译器(如 Babel、Webpack)无法直接修改你的代码字符串。它们必须先把代码转换成一种树状结构(JSON对象),这棵树精确地描述了代码的每一个部分(变量名、操作符、函数体)。如系列2所示,流程:源代码 -> 词法分析(Token) -> 语法分析 -> AST -> 修改/转换 -> 生成新代码。

下面代码可以很直观看到AST和我们编写代码的区别

javascript 复制代码
// 源代码
const a = 1;

// 对应的 AST (简化)
{
  "type": "VariableDeclaration", // 这是一个变量声明
  "kind": "const",               // 类型是 const
  "declarations": [
    {
      "type": "VariableDeclarator",
      "id": { "type": "Identifier", "name": "a" }, // 变量名 a
      "init": { "type": "Literal", "value": 1 }    // 初始值 1
    }
  ]
}

2.Vue 的 SFC 是什么?如何最大化利用?

答案:SFC,全称为:Single File Component,直译为单文件组件,是 Vue 的核心概念之一,指把一个组件的结构、逻辑、样式写在同一个 .vue 文件中。

下面是一个典型的SFC文件:

html 复制代码
<template>
  <div>{{ msg }}</div>
</template>

<script setup>
import { ref } from 'vue'

const msg = ref('Hello SFC')
</script>

<style scoped>
div {
  color: red;
}
</style>

vue这样做的优点:

1.高内聚:模板 + 逻辑 + 样式放在一起,方便维护

2.可编译优化:Vue 编译器可做静态提升、patch flag 等优化

3.强工程化支持:TS、CSS 预处理器、HMR、lint、tree-shaking

4.组件级作用域样式:避免样式污染

3. SSR 是什么?如何使用?

SSR,全称为Server-Side Rendering,服务端渲染,主要是指页面在服务器上先渲染成完整 HTML,再返回给浏览器展示,而不是等 JS 在浏览器执行后再生成页面。

以往都是客户端渲染,对比客户端渲染

CSR (客户端渲染):浏览器请求页面 -> 拿到空的 HTML -> 下载 JS -> JS 运行并把内容填进页面(首屏慢,爬虫抓不到内容)。

SSR (服务端渲染):浏览器请求页面 -> 服务器运行 Vue -> 生成完整的 HTML 字符串 -> 浏览器直接显示(首屏快,SEO 好)

如何使用?

vue可以使用Nuxt,打开SSR,React可以使用Next

4. Vue2 为什么无法监听数组变化,该如何做?

答案:Vue2 基于 Object.defineProperty,无法监听数组索引和 length 的变化,因此不能通过 arr[index] 或修改 length 触发更新。Vue2 通过重写数组的 7 个变异方法(push, pop, shift, unshift, splice, sort, reverse。只要你调用这 7 个方法,Vue 就能监听到)来实现数组响应式。正确做法是使用 splice 或 Vue.set。Vue3 是基于 ES6 Proxy(代理) 实现响应式,通过拦截对象和数组的所有基本操作(get / set / deleteProperty / has / ownKeys 等),统一做依赖收集和派发更新,因此可以完整监听数组索引、length 变化以及属性新增删除,不再需要像 Vue2 那样重写 Array 原型方法。

javascript 复制代码
//  错误做法 (Vue2 不会更新视图)
this.list[0] = '新的值';

//  正确做法 1: 使用重写的方法
this.list.splice(0, 1, '新的值');

//  正确做法 2: 使用 $set
this.$set(this.list, 0, '新的值');

5.keep-alive 是什么?react 如何实现类似功能?

答案:keep-alive 是 Vue 提供的内置抽象组件,用于在组件切换时缓存组件实例,而不是销毁,从而保留组件内部状态并减少重复创建带来的性能开销。被 keep-alive 包裹的组件不会触发 unmounted,而是通过 activated 和 deactivated 生命周期进行激活与失活。内部基于 key 维护缓存 Map,并通过 LRU 策略结合 max 属性控制缓存上限。

React 没有官方等价能力,因为 React 的设计是组件不在渲染树中就会被卸载。实际项目中通常通过样式隐藏、状态上提,或使用 react-activation 等第三方库来模拟组件缓存行为。

6. 什么时候用计算属性,什么时候用监听?

答案:computed 用于从已有响应式状态派生出新的状态,适合纯计算场景,具有缓存能力,依赖不变不会重复计算,强调声明式的数据关系。watch 用于在数据变化后执行副作用,比如发起接口请求、修改其他状态、路由跳转或与第三方库交互,属于命令式响应。原则上能用 computed 解决的派生数据不应该用 watch,watch 不用于计算新值,而用于处理变化带来的行为。

javascript 复制代码
// 场景:购物车总价 -> 用 Computed
const total = computed(() => price.value * count.value);

// 场景:搜索框输入停止 1秒 后自动搜索 -> 用 Watch
watch(searchText, (newVal) => {
  setTimeout(() => { api.search(newVal) }, 1000);
});

7. JS 中生成器和迭代器是什么,实际有什么应用?

答案:Iterator 是 ES 提供的统一遍历协议,通过 next 方法返回 value 和 done,使不同数据结构可以被 for...of、解构和扩展运算符统一遍历。Generator 是一种可以暂停和恢复执行的函数,用来更方便地创建迭代器,Generator 本身自动实现了 Iterator 和 Iterable 接口。它们的核心价值在于统一遍历接口、支持惰性计算以及可暂停的控制流。在工程中,Iterator 广泛用于 for...of 等语言特性,Generator 常用于自定义可遍历结构、惰性序列,以及在 redux-saga、Koa v1 等场景中用于复杂异步流程控制和流程编排。

实际使用示例:

javascript 复制代码
async function fetchUsers(page: number, pageSize: number) {
  const res = await fetch(`/api/users?page=${page}&pageSize=${pageSize}`)
  const data = await res.json()
  return data.list as User[]
}

async function* userIterator(pageSize = 100) {
  let page = 1

  while (true) {
    const list = await fetchUsers(page, pageSize)

    if (!list.length) {
      return
    }

    for (const user of list) {
      yield user   // 每次只 yield 一个用户
    }

    page++
  }
}

8. 什么是 TS 的 infer?如何使用?

答案:infer 是 TypeScript 条件类型中的关键字,用于在类型匹配过程中声明一个待推断的类型变量,从复杂类型结构中反向提取子类型。它常用于从函数类型中推断返回值和参数类型,从 Promise 中拆解返回值,从数组和元组中提取元素类型,以及在字符串模板类型中提取子串。TypeScript 内置的 ReturnType、Parameters、Awaited 等高级工具类型本质上都是基于 infer 实现的。infer 的核心价值是让类型具备模式匹配和结构拆解能力,从而减少重复类型定义并提升类型系统的表达能力。

例子(提取函数参数)

javascript 复制代码
type FnInfo<T> =
  T extends (...args: infer P) => infer R
    ? { params: P; return: R }
    : never

type Info = FnInfo<(id: number, name: string) => boolean>
// { params: [number, string]; return: boolean }

9.简要描述vite的原理

答案:Vite 在开发阶段基于浏览器原生 ES Module,通过 dev server 按需编译源码,不做全量打包,因此冷启动和热更新非常快。同时使用 esbuild 对第三方依赖进行预构建,统一为 ESM 并减少请求数量。在生产环境,Vite 使用 Rollup 进行静态打包,负责 Tree Shaking、代码分割和资源优化,从而兼顾开发体验和生产性能。

10. 简要说明如何最大支持 Tree Shaking?

答案:Tree Shaking 是基于 ES Module 静态分析的打包优化技术,用于在构建阶段移除未被使用的导出代码。它依赖 import/export 语法和无副作用模块设计,配合 sideEffects 标记和代码压缩工具,可以显著减少最终 bundle 体积并提升加载性能。

1.基于 ES Module 的命名导出 API确保项目是基于ES Module来进行的。

2.尽量用 export const func = ... 导出单个函数,而不是 export default { ... } 导出一个大对象(大对象很难被拆分优化)。

11.用math.random来计算抽奖概率会有什么问题?

答案:V8 引擎(Chrome/Node.js)底层使用的是 xorshift128+ 算法。这是一种确定性算法。只要拿到足够的历史数据序列,就能推算出内部状态(Seed),从而预测未来所有的随机数。对于涉及真金白银的抽奖,这是巨大的漏洞。虽然现代浏览器的算法改进了很多,但在某些特定数值范围内,Math.random() 并不是完美的均匀分布

解决方案:使用安全伪随机数生成器 (CSPRNG)

javascript 复制代码
// 1. 创建一个容器存放随机数
const array = new Uint32Array(1);
// 2. 填充真正的随机数 (基于物理噪声)
window.crypto.getRandomValues(array);
// 3. 归一化处理 (这一步比较复杂,简化理解为取模)
const winnerIndex = array[0] % userCount;

#总结

今天面试题就到这里,让我们每天学习几个题,一起成长。管他难易,获得成长就好。明天见。

相关推荐
鹏北海-RemHusband2 小时前
踩坑记录:iOS Safari 软键盘下的“幽灵弹窗“问题
前端·ios·safari
爱尔兰极光2 小时前
LeetCode 热题 100-连续最长序列
算法·leetcode·职场和发展
Warren982 小时前
一次文件上传异常的踩坑、定位与修复复盘(Spring Boot + 接口测试)
java·开发语言·spring boot·笔记·后端·python·面试
一位搞嵌入式的 genius2 小时前
深入理解浏览器中的 JavaScript:BOM、DOM、网络与性能优化
前端·javascript·网络·性能优化
lang201509282 小时前
一键生成Java Web项目:Tomcat-Maven原型解析
java·前端·tomcat
We་ct2 小时前
LeetCode 242. 有效的字母异位词:解法解析与时空优化全攻略
前端·算法·leetcode·typescript
执着2592 小时前
力扣hot100 - 104、二叉树的最大深度
算法·leetcode·职场和发展
indexsunny2 小时前
互联网大厂Java面试实录:Spring Boot微服务与Kafka消息队列实战解析
java·spring boot·微服务·面试·kafka·电商·技术解析
David凉宸2 小时前
Vue 3生态系统深度解析与最佳实践
前端·javascript·vue.js