公司S
2024 上半年
原型链: 如何通过a对象访问b对象的属性与方法
a.prototype.xxx = b
闭包:
对闭包的理解?
内部作用域中引用了外部变量, 好比房间内的一个小盒子里放着张留言的纸条
讲讲内存泄漏?
动态分配的内存没有被正确释放 1. 未声明的全局变量 2. 未被施放的定时器 3. 引用: 未被施放的闭包(变量引用) & 未被施放的DOM引用 function outer() { let bigData = new Array(1000000).fill('data'); return function inner() { console.log('Inner function'); }; } let leak = outer(); // 闭包引用,leak此时未被施放 --- 关于GC 引用计数: 每个对象都有一个引用计数,表示有多少个地方引用了它。当引用计数为0时,对象会被回收; 无法处理循环引用 标记清除: 标记: 从根对象开始,遍历所有可达对象并标记 清除: 遍历堆内存, 对不可达(标记)对象清除 需要暂停程序执行
如果在最外层有一个变量,闭包引用了该变量,GC会对其回收进行计数吗?
只要被调用之后,赋值的变量还存在,那这个被引用的变量就会存在 function outter(){ const quoteVar = 32; return function inner(){ console.log(quoteVar); } } const res = outter() // 存在 res = null; // 不存在
MVC和MVVM的区别
MVC 以React来说, 为单向数据流;数据驱动视图,为单向绑定,属于手动挡 MVVM 以Vue来说,为双向数据流;数据和视图双向驱动,为双向绑定,属于自动档
MVC的业务层有什么问题?
东西一旦多起来就会显得很冗余、沉重
讲讲浏览器和Node的事件循环
事件循环的作用是协调异步任务的执行顺序,确保主线程不会被阻塞,与异步对应的一个词是并发; 整体上, 先处理同步再处理异步 浏览器: 浏览器事件循环基于任务队列:宏任务(macro) && 微(micro)任务 在每一轮事件循环中,浏览器会执行以下操作: 执行JavaScript代码 处理事件(如点击、滚动等) 执行渲染(更新DOM、样式、布局等) Node: Node事件循环基于libuv库 timers (setTimeout、setInterval) Pending Callbacks Idle, Prepare Poll Check (setImmediate 在此阶段执行) Close Callback
nextTick在Node事件循环的哪个阶段执行?
执行时机与事件循环的阶段无关,而是在当前阶段切换之前执行 process.nextTick 的回调会在事件循环的每个阶段切换时立即执行,优先级高于微任务(如 Promise)和宏任务(如 setTimeout、setImmediate)
console.log('Start'); setTimeout(() => {console.log('Timeout');}, 0); setImmediate(() => {console.log('Immediate');}); Promise.resolve().then(() => {console.log('Promise');}); process.nextTick(() => {console.log('Next Tick');}); console.log('End'); --- Start End Next Tick Promise Timeout Immediate
AOP怎么在不修改原有代码的情况下,实现功能的更新?
AOP 的核心概念 切面(Aspect):封装横切关注点的模块,通常包含通知(Advice)和切点(Pointcut) 通知(Advice):定义在切点上执行的具体逻辑,例如在方法执行前、后或异常时执行 切点(Pointcut):定义哪些方法或代码段需要被切面拦截 连接点(Join Point):程序执行过程中可以插入切面的点,例如方法调用、异常抛出等 实现方式 动态代理(Dynamic Proxy) 装饰器模式(Decorator Pattern) 字节码增强(Bytecode Enhancement)
用自己的话讲讲React的实现机制
React 的核心机制基于虚拟 DOM(VDOM)和 Fiber 架构,通过合理利用浏览器的空闲时间来实现高效的页面渲染 Fiber 架构将渲染过程分为三个主要部分: 1. 调度器(Scheduler):负责任务的调度,利用浏览器的空闲时间(如 `requestIdleCallback`)将任务分片执行,避免阻塞主线程 2. 协调器(Reconciler): 负责虚拟 DOM 的 Diff 计算,找出需要更新的部分 React 使用 Fiber 节点(一种链表结构)来表示虚拟 DOM,每个 Fiber 节点包含 `child`、`sibling` 和 `return` 属性,通过深度优先遍历构建 Fiber 树 3. 渲染器(Renderer):负责将 Fiber 树的更新映射到实际的 DOM 操作(如插入、更新、删除节点) 具体地,React 的 Fiber 架构通过链表结构实现了可中断、可恢复的渲染过程 在协调阶段,React 会通过 Diff 算法比较新旧 Fiber 树,找出需要更新的节点,并生成副作用(如插入、更新、删除) Diff 算法通过同级比较和 key 优化,尽量减少不必要的 DOM 操作 此外,React 的 Hooks(如 `useState`、`useEffect`)也是基于 Fiber 架构实现的 其Hooks 的状态和副作用会被存储在 Fiber 节点中,并在适当的时机(如渲染完成后)执行
如果在给链表添加一个节点,添加到前边好还是后边好?
后边
如何做一个redux的管理机?
Redux 的本质是一个状态管理机 单一数据源:状态集中存储在 store 中 单向数据流:状态只能通过 action 和 reducer 更新 纯函数:reducer 是纯函数,确保状态更新的可预测性 Redux 的核心概念 Store:存储整个应用的状态。 Action:描述状态变化的普通 JavaScript 对象,通常包含一个 type 字段和可选的 payload 字段。 Reducer:一个纯函数,接收当前状态和一个 action,返回新的状态。 Dispatch:触发 action 的方法,store 会调用 reducer 来更新状态。 Subscribe:监听状态变化的方法,当状态更新时,触发回调函数。
function createStore(reducer) { let state; // 当前状态 let listeners = []; // 监听器列表 const getState = () => state; const dispatch = (action) => { // 调用 reducer 更新状态 state = reducer(state, action); listeners.forEach(listener => listener()); }; const subscribe = (listener) => { listeners.push(listener); return () => { listeners = listeners.filter(l => l !== listener); }; }; // 初始化状态 dispatch({ type: '@@INIT' }); return { getState, dispatch, subscribe }; } // Reducer function counterReducer(state = 0, action) { switch (action.type) { case 'INCREMENT': return state + 1; case 'DECREMENT': return state - 1; default: return state; } } const store = createStore(counterReducer); store.subscribe(() => { console.log('State changed:', store.getState()); }); store.dispatch({ type: 'INCREMENT' }); // State changed: 1 store.dispatch({ type: 'INCREMENT' }); // State changed: 2 store.dispatch({ type: 'DECREMENT' }); // State changed: 1
token具体在什么时候设置?
1. 用户登录成功后 2. Token的刷新 3. 用户注册成功后 4. 第三方登录成功后
存储流程是什么?
用户提交登录表单 服务器验证用户信息,生成 Token(如 JWT) 服务器将 Token 返回给客户端 客户端将 Token 存储在本地(如 localStorage) 客户端在后续请求中携带 Token(通常在 HTTP 请求头的 Authorization 字段中)
Electron的透明效果有什么问题?
不能鼠标穿透
公司Y
2024 下半年
把我当成小白,给我讲一个你觉得做的比较好的项目
RAG应用,梳理后核心就这几个东西 - Prompt:提问 & 提示词 - Embedding:词嵌入 - similarity_research:向量匹配 - Rerank:结果过滤
Embedding的过程具体起到什么用
1. Embedding 过程实际上是将高维、离散的数据映射到低维、连续的向量空间中。这种映射旨在保持数据在原始空间中的相似性,使得在向量空间中相近的嵌入向量表示的数据在原始空间中也是相似的。 2. 过程 a. 初始化 首先,需要定义嵌入向量的维度(即每个数据点将被映射到的向量的大小)。然后,通常随机初始化一个嵌入矩阵,其行数等于数据集中唯一数据点的数量,列数等于嵌入向量的维度。 b. 学习 在训练过程中,嵌入矩阵是通过优化一个目标函数来学习的。这个目标函数通常与任务相关,比如在推荐系统中,可能希望相似的物品有相近的嵌入向量。通过梯度下降等优化算法,模型会更新嵌入矩阵中的权重,使得相似的输入数据在嵌入空间中靠近,而不相似的则远离。 c. 优化 在学习过程中,可能会应用一些技巧来改善嵌入的质量,如使用负采样、正则化、dropout等。 d. 应用 一旦嵌入向量被学习好,它们就可以用于各种下游任务,比如文档相似度计算、推荐系统、图像分类等。
http和https的区别?https相比于http,安全性体现在哪方面
加密: http不加密,使用明文传输 https使用ssl和tls加密 认证: http不认证 https通过证书验证服务器身份 端口: 80 443 安全性: - https采用对称加密和非对称加密结合的方式 - https采用CA验证服务器身份 - 通过hash或mac(消息认证码)来保证数据完整性 - 序列号机制,防止重复信息的发送
浏览器缓存了解吗?有哪几种?
强缓存 浏览器直接使用本地缓存,不与服务器交互,直到缓存过期 字段:Expires,Cache-Control 协商缓存 浏览器每次请求资源都会与服务器进行通信,通过对比资源的修改状态来决定是否使用缓存 字段:Last Modified,Etag
为什么项目使用JWT而不使用Sessions作为认证?
JWT组成 head,通过base64编码 payload,指定算法加密 signature,指定密钥 JWT的特点 无状态,无需储存在服务器中 需要进行解码运算 跨域支持好 适合频繁认证的场景 Session的特点 存储于服务器, 有状态 灵活性高,可以随时删除 跨域支持一般 适合低频认证、需要高安全性的场景
tailwind对性能优化体现在什么方面
浏览器 JIT辅助开发 打包 purge、tree-shaking等减少打包体积 开发 Utility-First, 减少重复代码的书写、减少记忆成本
按输入监听即时查询的输入框和鼠标点击搜索才进行查询的输入框你认为他们各自在什么场景更合适
1. 搜索条件数量与复杂度 2. 搜索词与匹配词之间的匹配精确/模糊程度 3. 服务器性能开销 查了查还有其它方面可以说 - 用户体验(用户习惯 / 搜索体验 / 搜索效率 / 用户辅助-即时搜索与自动补全) - 安全性(即时搜索会暴露更多的数据)
讲讲你对闭包的理解
讲一讲http接口(get,post)
非技术上,面试官给我的建议
主要是自己比较紧张
- 手部动作有点多
- 声音可以适当放大一点
公司T
2024 下半年
讲解简历内容,挑一个你想讲的
其它全部都是常规问题
公司B (两轮)
2025 上半年, 游戏公司 一面, 基础面
上来直接笔试,写一道题
给一个字符串, 写一个函数, 函数需要返回一个词语出现次数的对象: 要求: 忽略大小写 & 不包括标点 返回结果格式: {"the": 5, "first":1, ...} "The new data center, the first of the company's kind in Latin America, will provide cloud computing services to local businesses and developers, underscoring Alibaba Cloud's commitment to accelerating Mexico's digital transformation and fostering innovation throughout the region."
毕业时间问题;前两家公司相关问题
讲一下闭包
讲一下React项目,你是怎么学习的,讲一下Scheduler和Reconciler
useEffect副作用清除:用React怎么写一个定时器,每秒输出+1:
const Timer = () => { const [count, setCount] = useState(0); useEffect(() => { const interval = setInterval(() => { setCount(prevCount => prevCount + 1); }, 1000); return () => clearInterval(interval); }, []); return ( <div> <h1>定时器: {count} 秒</h1> </div> ); };
讲一讲RAG项目,RAG部分是怎么做的;追问:表格处理你是怎么做的?
调用loader,没有太多可操作空间
二面,技术负责人面
做一个自我介绍
前两家公司做了什么,做的比较麻烦的点
讲讲SSR的过程以及具体原理
作用:在服务器端将页面渲染成 HTML,然后将渲染好的 HTML 发送给客户端,客户端接收到后可以直接展示,减轻客户端压力 过程: 请求发送:用户访问页面,请求发送到服务器 请求处理:服务器根据 URL 调用对应的路由处理函数 数据获取:服务器从数据库或 API 获取页面所需数据 渲染:服务器使用数据 + 前端框架(如 React/Vue)生成完整的 HTML 页面 返回结果:服务器将渲染好的 HTML 发送给客户端 客户端展示页面:客户端直接展示 HTML,用户看到页面内容 客户端激活(Hydration):客户端加载 JavaScript,将静态 HTML “激活”,使其具备交互能力 优点 SEO 友好:搜索引擎可以直接抓取服务器渲染的 HTML 页面,有利于 SEO 首屏加载速度快:用户首次访问页面时,可以直接看到完整的 HTML 内容,减少了白屏时间 更好的用户体验:尤其是在网络较慢或设备性能较差的情况下,SSR 可以提供更快的页面展示 SSR 的缺点 服务器压力大:每次请求都需要服务器进行渲染,增加了服务器的负载 开发复杂度高:SSR 需要处理服务器和客户端的代码兼容性问题,增加了开发复杂度 TTFB(Time to First Byte)可能较长:由于服务器需要处理数据和渲染页面,TTFB 可能会比 CSR 长
hydration的原理、过程、优点
Hydration( hydration 或 rehydration)是指在客户端接收到服务器渲染的 HTML 后,通过 JavaScript 将静态的 HTML 页面“激活”,使其具备交互能力的过程 过程: UI层面-HTML:客户端接收到服务器渲染的 HTML 页面后,直接展示页面内容 逻辑层面-JS:加载并执行JS 逻辑层面-Event:事件绑定 接管页面:客户端JS接管页面,后续的页面更新和交互将由客户端处理 优点: 保持 SEO 和首屏加载速度:Hydration 保持了 SSR 的优点,即 SEO 友好和首屏加载速度快 页面具备交互能力:通过 Hydration,页面在客户端具备了交互能力,用户可以正常操作页面 缺点: 潜在的 Hydration 不匹配问题:如果服务器渲染的 HTML 与客户端 JavaScript 生成的 DOM 结构不一致,可能会导致 Hydration 失败或页面显示异常。
你怎么理解fiber架构
调度器可以说是纵向延伸,抓住重点,比如利用好"暗时间" 协调器可以说是横向蔓延,顾全大局,比如锻炼身体、调整作息与饮食 当有重点又不失大局的时候,离成功(渲染 / 呈现)就不远了
instanceof的实现原理,即原型链;如何实现一个instanceof
原型链机制 每个对象都有一个隐式原型(__proto__),指向其构造函数的原型对象(prototype) 当访问一个对象的属性或方法时,如果对象本身没有该属性,JavaScript 会沿着原型链向上查找,直到找到该属性或到达原型链的顶端(null) instanceof 就是通过遍历原型链来判断对象的类型 instanceof的机制 对基本类型直接返回 false 检查对象的 __proto__ 是否与构造函数的 prototype 相等 如果不等,继续沿着原型链向上查找(即 obj.__proto__.__proto__,依此类推) 如果找到与构造函数的 prototype 相等的原型,返回 true 如果原型链顶端(null)仍未找到,返回 false function myInstanceof(obj, constructor) { if (typeof obj !== 'object' || obj === null) return false; let proto = Object.getPrototypeOf(obj); while (proto !== null) { if (proto === constructor.prototype) return true; proto = Object.getPrototypeOf(proto); } return false; } function myInstanceof(obj, constructor) { if (typeof obj !== 'object' || obj === null) return false; let proto = obj.__proto__; while (proto !== null) { if (proto === constructor.prototype) return true; // 核心代码 proto = proto.__proto__; } return false; }
RAG是什么?
Retrieval-Augmented Generation 是一种结合了检索(Retrieval)和生成(Generation)的模型架构,本身是一种架构形式,其包括了检索和生成这两部分
rag的embedding的作用是什么,embedding的优化有了解吗?
Embedding 能够捕捉文本的语义信息,使得 RAG 能够进行语义级别的检索和生成,而不仅仅是关键词匹配 流程 预处理(文本表示) 将文本(如问题、文档)转换为固定长度的向量表示 这种向量表示能够捕捉文本的语义信息,便于后续的检索和生成 检索 在检索阶段,RAG 使用 Embedding 来计算查询(如用户问题)与文档库中文档的相似度 通过 Embedding 的相似度计算,RAG 可以从文档库中检索出与查询最相关的文档 生成 RAG将检索的文档和查询输入给大模型 优化 预训练、微调、对比学习、负采样、多任务学习、维度优化、蒸馏
相似度计算了解吗?比如余弦相似度
余弦相似度的特点 优点 不受向量长度影响:余弦相似度只关注向量的方向,而不关心其大小,因此适用于高维稀疏向量(如文本的 TF-IDF 或 Embedding 表示) 计算简单高效:适合大规模数据的相似度计算 缺点 无法捕捉绝对距离:如果两个向量的方向相同但长度差异很大,余弦相似度仍然会很高 对噪声敏感:在高维空间中,稀疏向量之间的余弦相似度可能不够稳定
常见相似度计算方法 余弦相似度(Cosine Similarity) 欧氏距离(Euclidean Distance) 混合检索(Hybrid Search) 重排序(Reranking) 基于知识图谱的相似度计算 对比学习(Contrastive Learning) & 动态 Embedding
rag的chunk overlap的机制与原理
Chunk Overlap 的定义 Chunk:将长文档分割成多个较小的文本块(chunks),每个块包含一定数量的文本(如 256 个 token) Overlap:在分割时,相邻的两个块之间会有部分重叠的文本(如 32 个 token) 优点 避免信息丢失:确保关键信息完整地出现在至少一个块中 上下文连续性:保留文本的上下文信息,提升语义理解能力 提高检索精度:增加候选文档的多样性,提高召回率 缺点 增加计算开销:重叠分块会增加块的数量,导致检索和生成的计算量增加 冗余信息:重叠部分可能引入冗余信息,增加模型的输入长度
rerank的机制和原理讲一下
Rerank 的原理 (1)两阶段检索 Rerank 是一种两阶段检索策略 召回阶段(初步检索):使用快速检索方法召回大量候选文档 排序阶段(重排序):使用重排序模型对候选文档进行精细化排序 (2)语义理解 重排序模型能够捕捉查询和文档之间的语义关系,而不仅仅是字面匹配 例如,BERT 等预训练语言模型可以通过上下文理解查询和文档的语义 (3)精细化排序 重排序模型会为每个候选文档计算一个相关性得分(similarity score), 并根据得分进行排序 通过精细化排序,可以显著提高检索结果的准确性
你想怎么进一步优化你的项目
cookie的组成以及流程
看一下浏览器: Name / Value Domain Path Expires(Max-Age) Size HttpOnly:标志防止 JavaScript 访问 Cookie,避免 XSS 攻击 Secure:确保 Cookie 仅通过 HTTPS 传输 SameSite:标志防止 CSRF 攻击 注意事项: 大小限制 每个 Cookie 的大小通常限制为 4KB。 每个域名下的 Cookie 总数也有限制(通常为 20 个左右) 性能: Cookie 会在每次请求中发送到服务器,过多的 Cookie 会增加请求的开销
反问:公司的部门;公司的业务;卷吗;有没有人带
公司D(两轮)
公司性质为初创公司,技术驱动 我讲述的原则是实事求是 看中了我两方面:
- 写过一个React内核,基本上不需要再记录
- 搞过RAG
第一面 基础面
自我介绍
讲述前两家实习的公司,重点问了SSR;上传和下载涉及到大文件了吗
涉及到大文件: 1. 分块上传(Chunked Upload) 原理:将大文件分割成多个小块(如 5MB/块),逐块上传到服务器 优点: 减少单次上传的数据量,降低网络传输压力 支持断点续传,提升上传的可靠性 实现方式: 前端使用 File.slice() 方法将文件分块 后端接收分块并逐步合并文件 工具: 前端:axios、fetch 支持分块上传 后端:multer(Node.js)、Flask(Python)等支持分块接收 2. 断点续传(Resumable Upload) 原理:记录已上传的文件块,支持从中断处继续上传 优点: 避免网络中断导致的上传失败 提升用户体验 实现方式: 前端记录已上传的块信息(如块索引、块大小) 后端根据块信息合并文件 工具 前端:tus-js-client(基于 tus 协议) 后端:tusd(基于 tus 协议的服务端实现) 3. 压缩上传 原理:在上传前对文件进行压缩,减少传输数据量 优点: 减少网络传输时间 节省存储空间 实现方式: 前端使用 pako 或 zlib 进行压缩 后端解压缩并存储文件 4. 异步上传 原理:将上传任务放到后台异步处理,避免阻塞主线程 优点: 提升用户体验 支持批量上传 实现方式 前端使用 Web Worker 或 Promise 实现异步上传 后端使用消息队列(如 RabbitMQ、Kafka)处理上传任务
讲述MiniReact怎么做的
讲述Rag怎么做的
React和Vue喜欢哪个
简要讲述了一下业务与职责
HR环节:如果让你来公司你偏向做哪方面的工作
第二面 CEO面
先是给看了一段视频,问一下对目前的项目的看法
前两家公司相关的问题
Vue和React喜欢哪个;如果我们抛弃这两个框架,你会怎么做? 答了svelte 或者 vanilla
Rag是怎么做的,有了解主流方案比如cursor是如何优化匹配结果的吗
特定的 Embedding 模型 技术:使用专门针对代码训练的 Embedding 模型(如 CodeBERT、GraphCodeBERT) 作用: - 捕捉代码的语法和语义信息 - 提升代码片段与查询的匹配精度 混合检索(Hybrid Search) 技术:结合稀疏检索(如 BM25)和稠密检索(如 Embedding) 作用: - BM25 用于字面匹配,Embedding 用于语义匹配 - 兼顾召回率和准确率 重排序(Reranking) 技术:使用基于 Transformer 的重排序模型(如 BERT、RoBERTa) 作用: - 对初步检索到的候选文档进行精细化排序 - 提高生成模型输入的质量 上下文感知检索 技术:多跳检索(Multi-hop Retrieval)和上下文增强 作用: - 在检索时考虑代码的上下文(如函数定义、类结构) - 提升复杂查询的匹配效果 实时索引更新 技术:使用 Merkle 树结构检测代码变化,并定期刷新索引 作用: - 保证索引的及时更新 - 避免不必要的重复计算,提升检索效率 分块与重叠策略 技术:将代码分割成较小的块(chunks),并在相邻块之间设置重叠部分(overlap) 作用: - 避免关键信息丢失 - 保留上下文信息,提高检索的召回率和精度 检索评估器(Retrieval Grader) 技术:轻量级的“检索评估器”为每个检索到的文档返回一个置信度分数 作用: - 根据置信度分数决定是否触发新的检索操作或对现有文档进行知识细化 - 提高检索结果的可靠性 多模态索引 技术:支持多模态数据(如代码、文档、图像)的索引和检索 作用: - 使用特殊嵌入方法(如 ColBERT)生成上下文相关的向量 - 提升复杂查询的响应时间和准确性 对比学习(Contrastive Learning) 技术:通过对比学习训练 Embedding 模型和重排序模型 作用: - 提升模型的区分能力 - 使相关文档的得分更高,不相关文档的得分更低 知识蒸馏(Knowledge Distillation) 技术:将大型模型(如 BERT)的知识蒸馏到小型模型中 作用: - 提升小型模型的性能 - 减少计算开销 动态 Embedding 技术:根据上下文动态调整 Embedding 表示 作用: - 提升语义匹配的准确性 - 适应复杂的查询场景 异步处理 技术:将检索和生成任务放到后台异步处理 作用: - 提升系统的并发处理能力 - 改善用户体验 缓存机制 技术:使用缓存存储频繁访问的检索结果 作用: - 减少重复计算,提升检索效率 - 降低系统负载 分布式计算 技术:使用分布式计算框架(如 Spark、Flink)处理大规模数据 作用: - 提升系统的可扩展性和性能 - 支持海量数据的实时检索
rerank的作用讲一下
对Docker和K8s是了解还是折腾过?
有多少项目是自己写的
预期薪资是多少,可以往高点说
手上目前有几个offer 能透露一下你下一家公司的名字吗
给出面试结果以及建议:关于沟通上比较担心