前言
这次面试算是我的首次战斗,在元宵过后开投 , 我觉得其重要性犹如南昌八一广场打响的第一枪 , 战争正式开始了 , 我拿着大二的“小卡拉米简历” 广泛撒网 ,经历了很多次“已读不回” ,也是约来一次面试 , 直接看面经
一面:
二面:
下面做简介 , 后期闭关将会深入些文章 ~ , 点赞关注不迷路 , 给你新鲜的面经!
一面要点
1. 原型链
深度解析:
原型链是 JavaScript 实现继承的核心机制。每个对象都有一个隐藏属性 [[Prototype]]
(可通过 __proto__
或 Object.getPrototypeOf
访问),指向其原型对象。当访问一个对象的属性时,如果对象本身没有该属性,JavaScript 会沿着原型链向上查找,直到找到该属性或到达原型链的顶端(null
)。
- 原型链的终点:所有对象的原型链最终都会指向
Object.prototype
,而Object.prototype
的原型是null
。 - 构造函数与原型:每个构造函数都有一个
prototype
属性,指向其原型对象。实例对象的__proto__
指向构造函数的prototype
。 - 性能问题:原型链过长会导致属性查找效率降低,尤其是在深层嵌套的原型链中。
示例:
function Person(name) {
this.name = name;
}
Person.prototype.sayName = function() {
console.log(this.name);
};
const person = new Person('Alice');
person.sayName(); // 输出: Alice
console.log(person.__proto__ === Person.prototype); // true
console.log(Person.prototype.__proto__ === Object.prototype); // true
console.log(Object.prototype.__proto__ === null); // true
2. 实现继承
深度解析:
JavaScript 的继承方式有多种,每种方式都有其适用场景和优缺点。
- 原型链继承:
function Parent() {
this.name = 'Parent';
}
Parent.prototype.sayName = function() {
console.log(this.name);
};
function Child() {}
Child.prototype = new Parent(); // 继承
const child = new Child();
child.sayName(); // 输出: Parent
- 优点:简单,易于实现。
- 缺点:所有实例共享原型属性,修改一个实例的原型属性会影响其他实例。
2. 构造函数继承:
function Parent(name) {
this.name = name;
}
function Child(name) {
Parent.call(this, name); // 继承属性
}
const child = new Child('Alice');
console.log(child.name); // 输出: Alice
- 优点:可以传递参数,避免共享属性。
- 缺点:无法继承父类原型上的方法。
3. 组合继承:
function Parent(name) {
this.name = name;
}
Parent.prototype.sayName = function() {
console.log(this.name);
};
function Child(name) {
Parent.call(this, name); // 继承属性
}
Child.prototype = new Parent(); // 继承方法
const child = new Child('Alice');
child.sayName(); // 输出: Alice
- 结合原型链继承和构造函数继承的优点。
- 缺点:父类构造函数被调用两次,性能开销较大。
4. 寄生组合继承:
function Parent(name) {
this.name = name;
}
Parent.prototype.sayName = function() {
console.log(this.name);
};
function Child(name) {
Parent.call(this, name); // 继承属性
}
Child.prototype = Object.create(Parent.prototype); // 继承方法
Child.prototype.constructor = Child;
const child = new Child('Alice');
child.sayName(); // 输出: Alice
- 最优解决方案,避免了组合继承的缺点。
- 使用 `Object.create` 创建原型链,避免调用父类构造函数。
3. 虚拟 DOM
深度解析:
虚拟 DOM 是 React 的核心技术之一,用于优化 UI 更新的性能。
- 工作原理:
- 虚拟 DOM 是一个轻量级的 JavaScript 对象树,表示真实 DOM 的结构。
- 当状态发生变化时,React 会生成新的虚拟 DOM 树,并与旧的虚拟 DOM 树进行对比(Diff 算法)。
- 通过对比,React 计算出最小的 DOM 操作,然后批量更新真实 DOM。
- Diff 算法:
- 层级对比:React 只会对比同一层级的节点,不会跨层级对比。
- Key 的作用:通过
key
属性标识节点,帮助 React 识别哪些节点是新增、删除或移动的。
- 优点:
- 减少直接操作真实 DOM 的次数,提高性能。
- 提供跨平台能力(如 React Native)。
- 缺点:
- 虚拟 DOM 的创建和对比需要额外的计算开销,对于简单页面可能不如直接操作 DOM 高效。
4. 对 TS 的了解程度
深度解析:
TypeScript 是 JavaScript 的超集,添加了静态类型系统,适合大型项目开发。
- 核心特性:
- 类型注解:通过
: type
语法为变量、函数参数和返回值添加类型。 - 接口:定义对象的结构,支持可选属性和只读属性。
- 泛型:提高代码的复用性和类型安全性。
- 装饰器:用于元编程,常用于 Angular 框架。
- 类型注解:通过
- 工具链:
- tsc:TypeScript 编译器,将 TS 代码编译为 JS。
- tsconfig.json:配置文件,定义编译选项。
- 实际应用:
- 在 React 项目中,使用 TypeScript 可以显著提高代码的可维护性,减少运行时错误。
5. React 和 Vue 你爱谁?
深度解析:
React 和 Vue 都是优秀的前端框架,但设计哲学和适用场景不同。
- React:
- 优点:
- 灵活,生态丰富(如 Redux、React Router)。
- 函数式编程思想,适合大型项目。
- 缺点:
- 学习曲线较陡峭。
- JSX 语法需要适应。
- 优点:
- Vue:
- 优点:
- 模板语法直观,易于上手。
- 官方工具链完善(如 Vuex、Vue Router)。
- 缺点:
- 灵活性较低,生态相对较小。
- 优点:
个人倾向:
我更倾向于 React,因为它的函数式编程思想和 JSX 语法让我感到更加自由和高效。
6. 项目部署经验?Docker?
深度解析:
- 项目部署:
- 使用 CI/CD 工具(如 Jenkins、GitLab CI)实现自动化部署。
- 通过 Nginx 配置反向代理和负载均衡。
- Docker:
- 使用 Dockerfile 定义镜像构建步骤。
- 使用 Docker Compose 管理多容器应用。
- 通过 Kubernetes 实现容器编排。
7. 状态管理?底层原理?
深度解析:
- 状态管理工具:
- Redux:基于单向数据流,通过 Action 触发 Reducer 更新 Store。
- MobX:基于响应式编程,通过观察者模式自动更新状态。
- Context API:React 内置的状态管理工具,适合小型项目。
- Redux 底层原理:
- Store:存储全局状态。
- Action:描述状态变化的动作。
- Reducer:纯函数,根据 Action 更新状态。
- Middleware:扩展 Redux 功能(如异步操作)。
我对 redux 理解深一点
8. 观察者模式和发布订阅
深度解析:
- 观察者模式:
- Subject 维护一组 Observers,状态变化时通知 Observers。
- 强耦合,Subject 需要知道 Observers 的存在。
- 发布订阅模式:
- 通过 Event Bus 解耦发布者和订阅者。
- 发布者不需要知道订阅者的存在。
这篇不错 :
9. IoC 和 DI
深度解析:
- IoC(控制反转):
- 将对象的创建和依赖关系的管理交给外部容器。
- 降低代码耦合度。
- DI(依赖注入):
- 通过构造函数、属性或方法注入依赖对象。
- 提高代码的可测试性和可维护性。
10. LangChain 框架解决了什么问题?
深度解析:
LangChain 是一个用于构建基于大语言模型(LLM)应用的框架,解决了以下问题:
- 外部数据集成:将 LLM 与外部数据源(如数据库、API)集成。
- 工具链支持:提供预定义的工具链(如搜索、计算)。
- 记忆管理:通过 Memory 模块管理对话历史。
11. 什么是 RAG?
深度解析:
RAG(Retrieval-Augmented Generation)是一种结合检索和生成的模型架构:
- 检索阶段:从外部知识库中检索相关信息。
- 生成阶段:将检索到的信息与输入一起输入生成模型,生成更准确的输出。
12. 向量嵌入
深度解析:
向量嵌入是将高维数据映射到低维向量空间的技术:
- 应用场景:文本分类、语义搜索、推荐系统。
- 常用算法:Word2Vec、GloVe、BERT。
13. 相似性检索的原理
深度解析:
- 计算相似度:通过余弦相似度、欧氏距离等度量向量之间的距离。
- 算法:KNN(精确检索)、ANN(近似检索)。
14. AI 流式输出的底层原理
深度解析:
- 逐步生成:模型逐步生成输出序列,每一步都依赖于前一步的输出。
- 输出缓冲:通过缓冲区逐步返回部分结果。
15. 大模型是如何推理的?
我浅浅的说了下
- 自注意机制
- 和基于概率的涌现性智能观点
专业的看下:
zhuanlan.zhihu.com/p/628511161
16. 各类模型的对比
主要讲了下哪些模型擅长什么
- deepseek v3 deepseek r1
- gpt
- claude
- ....
zhuanlan.zhihu.com/p/167261751…
17. 是否发布模型?
没有 , 回答了一些 coze 智能体的发布和 魔搭社区的应用
18. 如何实现 LangChain Memory
可以看看我的专栏 :juejin.cn/post/746337…
二面要点
大文件上传:juejin.cn/post/746723…
算法在项目中的应用
- 贪心算法
- 任务调度:在生产调度、工作流管理场景中,存在多个需按序执行且耗费时间和资源的任务。例如,一台机器一天内要完成多个工作量不同的任务,使用贪心算法,每次选择工作量最小的任务先做,能在有限时间内完成尽可能多的任务,提高生产效率。实际应用中还会结合任务优先级、资源限制、任务依赖关系等因素灵活调整 。
- 背包问题(部分情况):在简单的背包问题里,已知背包容量固定,有多种物品,每个物品有各自的重量和价值,贪心算法可依据价值重量比(或其他策略),优先选择能使背包价值增加最多的物品放入,直到背包装满 。
- 最短路径(部分算法):像 Dijkstra 算法,用于求单源最短路径,是贪心算法的典型应用。每次选择距离源点最近且未确定最短路径的顶点,更新其邻接顶点的距离,逐步确定所有顶点的最短路径 。
- 股票交易:在交易次数无限制,且任何时候最多持有一股股票的情况下,只要股票价格上涨就进行交易获取利润,通过统计所有上涨带来的利润,得到最大收益 。
- 动态规划
- 资源分配:当项目资源有限,需分配给多个子项目或任务时,动态规划可通过分析不同分配方案下的收益情况,考虑资源约束和各子项的依赖关系等,找到使总收益最大的资源分配策略。比如,将有限的研发资金分配到不同产品的研发中 。
- 最优路径规划:在地图导航等场景中,要考虑路况、距离、时间等多个因素找到从起点到终点的最优路径。动态规划可将路径问题分解为多个子问题,通过求解子问题并记录结果,避免重复计算,从而高效找到最优解 。
- 最长公共子序列:在文本处理、版本控制等领域,比较两个序列(如文本段落、代码版本)的相似性时,可利用动态规划找出它们的最长公共子序列,从而确定修改、添加或删除的部分 。
- 生产库存管理:考虑生产成本、库存成本、市场需求的不确定性等因素,动态规划能帮助制定最优的生产和库存策略,以最小化总成本 。
总结
首站大捷 , 然长路漫漫 , 大二财哥已然薪水 550 / 天, 实现我团首富 , 我当脚踏实地 , 仰望星空 ~ , 争取可以看到他的后背🤡 ~