最近不是差不多秋招提前批了吗?我就去面了几家,我把我面试的题目分享并且试着解析给jym。希望对jym有所帮助(●'◡'●)
秋招面试题
移动端项目和web项目区别
这道题是道比较开放的题目,也是我最开始被问到的几道题目之一,说实话我当时回答的不知所云,哈哈。
后来查资料,我发现,这道题关键是要讲的是核心的差异。
示例回答:
移动端和 Web 项目的核心区别在于运行环境和交付方式。
移动端 App 运行在 iOS/Android,需要打包和发布,体验更流畅,也能调用系统硬件能力,但更新成本相对高;Web 项目则运行在浏览器中,不需要安装,迭代快,维护成本低,但受限于浏览器,性能和交互会差一些。
通常,用户高频使用、需要硬件支持的场景更适合做移动端,而信息展示、后台管理这类项目用 Web 就更高效。
在实际项目里,我也接触过跨平台方案,比如 React Native、Flutter 或者 PWA,用来平衡体验和开发效率。
介绍hooks组件
面试里如果让你 介绍 Hooks 组件,他们通常想听到:
- 你是否理解 React Hooks 的核心概念。
- 你能否说明 Hooks 相对 class 组件的优势。
- 你能否举例说明常用的 Hooks。
面试思路
- 先解释 Hooks 是什么
React Hooks 是 React 16.8 引入的一种新特性,让函数组件可以使用 state、生命周期以及其他 React 特性,而不必写 class 组件。
- 说明为什么有 Hooks(解决了什么问题)
- 复用逻辑更方便:class 组件里逻辑复用需要 mixin 或 HOC,比较复杂;Hooks 可以通过自定义 Hook 来抽离逻辑。
- 代码更简洁:函数式编程风格更直观,避免了 this 绑定问题。
- 状态逻辑更清晰:相关逻辑可以写在一起,不像 class 组件里分散在不同生命周期方法中。
- 常用的内置 Hooks
useState:在函数组件中添加状态。useEffect:处理副作用(如请求数据、订阅事件、操作 DOM)。useContext:共享上下文数据。useReducer:更复杂的 state 管理(类似 Redux)。useMemo/useCallback:性能优化,避免不必要的渲染或函数重新创建。useRef:获取 DOM 或保存跨渲染周期的变量。
- 掌握主动权
你可以顺势介绍useRef的相关的知识点,比如受控组件和非受控组件啊,useMemo再扯到懒加载啊。或者讲到react 16引进的函数组件、类组件的区别啊,或者react 类组件的生命周期啊等等......
- 最后总结
Hooks 让函数组件拥有状态和生命周期,更容易复用逻辑、代码更简洁,已经逐渐取代 class 组件成为主流开发方式。这里也可以提一嘴自定义hooks,加分项哦!
面试要掌握主动权
react 和 vue 相比有什么区别
React 和 Vue 的主要区别在于设计理念和数据绑定。
React 更像一个 UI 库,强调函数式编程和单向数据流,灵活度高,但需要搭配社区库;Vue 是渐进式框架,自带路由、状态管理,双向绑定写法更直观,上手快。
在性能上,React 需要手动做一些优化(如 memo、useCallback),而 Vue 通过响应式系统可以更自动化地追踪依赖。
如果是大型复杂项目,React 更适合;如果是中小型快速开发,Vue 更高效。
从响应式方面来回答的话:
响应式的核心思想是数据驱动视图,数据变化时视图会自动更新。
Vue2 是基于 Object.defineProperty 的 getter/setter 实现响应式,Vue3 改用 Proxy,更完善地支持对象新增、删除和数组变化。Vue 的响应式是依赖追踪的,某个数据变化,只会触发相关视图更新。
React 的实现方式不同,它不是自动依赖追踪,而是通过状态驱动:当 setState 或 useState 更新时,整个组件重新渲染,再通过虚拟 DOM diff 更新需要变化的部分。
所以 Vue 的更新粒度更细,而 React 需要配合 memo、useCallback 等优化。
你了解es6这个框架吗
这里要注意一点哈 🙂,ES6 不是一个框架,而是 ECMAScript 2015 的简称,是 JavaScript 的一个版本标准。
很多面试官会故意这样问,想考你是否能分清楚 语言标准 vs 框架/库。
如果你直接说 “ES6 不是框架”,反而能显得你很专业。
首先澄清一下,ES6 并不是框架,它是 ECMAScript 2015,是 JavaScript 的一个重要版本更新,引入了很多新的语法和特性,极大地提升了开发效率和代码可维护性。
在 ES6 中,比较核心和常用的特性包括:
- 变量声明:
let和const,解决了var没有块级作用域、变量提升等问题。 - 箭头函数:简化了函数写法,并且不会改变
this指向,常用于回调函数。 - 模板字符串:用反引号 `,支持多行字符串和字符串插值,让字符串拼接更直观。
- 解构赋值 & 扩展运算符:快速提取对象/数组里的数据,或者用
...实现数组/对象的合并、浅拷贝。 - 模块化:引入了
import和export,让前端代码可以更清晰地组织,替代了早期的全局变量或 CommonJS。 - Promise:用于更优雅地处理异步逻辑,也为后续的
async/await奠定了基础。 - 新增数据结构:比如
Map、Set,解决了传统对象和数组在某些场景下的局限性。
总结来说,ES6 不是框架,而是 JavaScript 的一次标准升级。它带来的模块化、箭头函数、解构赋值、Promise 等特性,让代码更简洁、更易读,也为现代前端框架(比如 React、Vue、Angular)的发展提供了语言层面的支持。
然后面试官就问我了: es6的展开运算符是深拷贝还是浅拷贝?
es6的展开运算符是深拷贝还是浅拷贝
这个时候你可以先解释一遍概念,什么是深拷贝,什么是浅拷贝。一方面让面试官认为你对概念非常清晰,加分,一方面又留下了时间给你回忆思考知识点。嘛,最重要的是增添面试时长哈哈。
面试官,我先来介绍一下深拷贝和浅拷贝吧。深拷贝和浅拷贝的本质区别在于 拷贝的“层级” :
- 浅拷贝只拷贝对象的 第一层属性,内部引用类型仍共享。
- 深拷贝会递归拷贝 所有层级,内部对象完全独立。
浅拷贝(Shallow Copy)
-
拷贝对象的第一层属性。
-
基本类型拷贝值,引用类型拷贝地址。
-
常用方法:
- 对象:
Object.assign({}, obj)、{ ...obj } - 数组:
slice()、concat()、[...arr]这里就顺势说了...展开运算符是浅拷贝了
- 对象:
深拷贝(Deep Copy)
-
拷贝对象的 所有层级属性,内部引用类型也会复制一份独立副本。
-
常用方法:
JSON.parse(JSON.stringify(obj))(加分点:函数、undefined、Symbol、循环引用会丢失)
这里说完JSON.parse丢失的问题后,可以提出我们自己的自定义深拷贝,这里展示代码给你们看:
function clone(target, map = new WeakMap()) {
if (typeof target === 'object') {
let cloneTarget = Array.isArray(target)?[]:{};
if (map.get(target)) {
return map.get(target);
}
map.set(target, cloneTarget);
for (const key in target) {
cloneTarget[key] = clone(target[key], map);
}
return cloneTarget;
} else {
return target;
}
}
for of 循环有了解吗?
面试时如果被问到 for…of 循环,可以先解释它的 作用、特点、与其他循环的区别
for…of 是 ES6 新增的循环语法,用来遍历 可迭代对象,如数组、字符串、Set、Map 等。
与 for…in 不同,它遍历的是 元素的值 而不是键名,也比传统 for 循环更简洁。
在实际开发中,我常用它遍历数组、Set 或 Map,代码可读性和可维护性都更好。
如果你想要掌握面试主动权,拉长面试时间。
其实我们可以从可迭代对象这里扯到属性描述符。
JavaScript 对象的每个属性都有一个 属性描述符(Property Descriptor) ,用来控制属性的行为,包括:
writable:是否可写enumerable:是否可枚举configurable:是否可配置value或get/set:属性的值或访问器函数
可以用Object.getOwnPropertyDescriptor(obj, 'prop')查看,也可以用Object.defineProperty来设置。
promise 回调地狱问题如何去解决
这是前端面试中非常经典的问题,重点是 理解回调地狱的本质 + 掌握 Promise/async-await 的解决方案。
面试回答思路
什么是回调地狱
回调地狱(Callback Hell)是指异步操作层层嵌套回调函数,导致代码可读性差、维护困难、错误处理复杂的现象。
示例:
doSomething(function(result1) {
doSomethingElse(result1, function(result2) {
doThirdThing(result2, function(result3) {
console.log(result3);
});
});
});
Promise 的解决方案
- Promise 将异步操作封装成对象,使用
.then()链式调用,避免回调嵌套。
doSomething()
.then(result1 => doSomethingElse(result1))
.then(result2 => doThirdThing(result2))
.then(result3 => console.log(result3))
.catch(err => console.error(err));
优点:
- 链式调用,平坦化代码结构
.catch()可以统一处理错误
async/await 的解决方案(更现代)
- ES8 引入
async/await,可以用同步风格写异步代码,极大提高可读性
async function main() {
try {
const result1 = await doSomething();
const result2 = await doSomethingElse(result1);
const result3 = await doThirdThing(result2);
console.log(result3);
} catch (err) {
console.error(err);
}
}
main();
优点:
- 代码像同步流程,可读性强
- 错误统一用
try/catch捕获 - 与 Promise 完全兼容
面试回答示例
回调地狱是异步操作层层嵌套回调导致的可读性差、维护困难的问题。
解决方案:
- Promise:通过
.then()链式调用平铺回调,同时.catch()统一错误处理。 - async/await:将异步操作写成同步风格,用
await获取结果,try/catch统一处理异常,可读性更好。
这两种方式都可以避免回调地狱,提高代码可维护性。
async 和 await
async和 await 是在ES2017(也叫 ES8) 中引入的。
async 用于声明异步函数,返回 Promise;
await 用于等待 Promise 结果,使异步代码像同步流程一样写,提升可读性。
错误处理用 try/catch 或 .catch()。
并行异步处理可以用 Promise.all(),串行则直接 await 多个操作。
async/await 本质上不会阻塞主线程,是基于 Promise 的语法糖。
这里可以扩展promise.all和 promise.race,可以讲event-loop事件循环机制。
日常开发过程中你用过哪些组件库
这里可以讲UI组件库:ant design, react-vant
还有hooks组件库:阿里的ahooks组件库
css怎么实现居中
这里居中就可以讲很久了。如果你对居中非常熟悉,可以拆分成
- 行内元素
- 水平居中
- 垂直居中
- 块级元素
- 固定宽高块级盒子水平垂直居中
- 不固定宽高块级盒子水平垂直居中
行内元素
行内元素都比较简单,就简单带过吧。
水平居中
采用text-align
text-align: center;
单行文本垂直居中
单行文本可用 line-height 等于容器高度
height: 50px;
line-height: 50px;
块级元素
固定宽高块级盒子水平垂直居中
适用场景:父元素已知高度,子元素宽高固定。
- absolute + margin 负值 缺点需要知道盒子宽高
- absolute + margin auto (重要)
- absolute + calc (css calc 计算函数) 缺点是性能差,很少用
absolute + margin 负值
.child {
position: absolute;
top: 50%;
left: 50%;
width: 200px;
height: 100px;
margin-left: -100px; /* 宽度的一半 */
margin-top: -50px; /* 高度的一半 */
}
-
原理:先用
top/left: 50%把元素左上角移动到父元素中心,再用负 margin 把中心点对齐。 -
缺点:必须知道宽高,否则无法正确居中。
absolute + margin auto
.parent {
position: relative;
}
.child {
position: absolute;
top: 0; bottom: 0; left: 0; right: 0;
width: 200px;
height: 100px;
margin: auto;
}
-
原理:设置
top/right/bottom/left: 0并且margin: auto,块元素会在父容器中居中。 -
优点:无需计算负值,推荐使用。
-
缺点:仍需知道宽高才能居中。
absolute + calc()
.child {
position: absolute;
width: 200px;
height: 100px;
top: calc(50% - 50px); /* 50% - 高度一半 */
left: calc(50% - 100px); /* 50% - 宽度一半 */
}
-
原理:用
calc()计算偏移量,使元素中心对齐父容器中心。 -
缺点:性能稍差,代码可读性不如 margin auto,现代开发很少用。
不固定宽高块级盒子水平垂直居中
适用场景:子元素宽高不确定,或者内容自适应。
absolute + transform
.child {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
-
原理:top/left 移动到父元素中心,
translate(-50%, -50%)把元素自身中心移动到该位置。 -
优点:不需要知道宽高,通用性强。
line-height + vertical-align
.parent {
height: 100px;
line-height: 100px; /* 与高度相等 */
text-align: center;
}
.child {
display: inline-block;
vertical-align: middle;
}
-
原理:利用行高让单行文本或行内块元素垂直居中。
-
缺点:只能用于单行文本或 inline-block 元素,不适合多行内容。
writing-mode
-
改变文本流方向,让垂直方向变为水平方向,然后再用 text-align 居中。
-
应用场景:文本或特殊布局,不常用,属于 CSS 冷门技巧。
.parent {
writing-mode: vertical-rl;
text-align: center;
}
注意:
-
writing-mode不是行内元素居中方案 -
它作用于 块级元素(容器),通过改变文本方向间接影响内容居中
-
面试讲时可以说:
writing-mode是改变块级文本书写方向的属性,可以配合text-align实现居中,但属于冷门方法,不推荐做一般居中使用
table-cell
.parent {
display: table;
width: 100%;
height: 200px;
}
.child {
display: table-cell;
vertical-align: middle;
text-align: center;
}
-
原理:利用 table-cell 的
vertical-align: middle属性实现垂直居中。 -
优点:兼容旧浏览器
-
缺点:语义上不太直观,不推荐现代开发使用。
Flex 布局(现代推荐)
.parent {
display: flex;
justify-content: center; /* 水平居中 */
align-items: center; /* 垂直居中 */
}
优点:
- 简洁易懂
- 支持多行多元素
- 不依赖子元素宽高
Grid 布局(现代推荐)
.parent {
display: grid;
place-items: center; /* 同时水平+垂直居中 */
}
优点:
- 语义清晰
- 代码最简洁
- 支持复杂布局
恭喜你一口气看到了这里呀,如果累了,记得休息一下,其实我也敲累了😵💫
ok, 整顿完毕,让我们一口气干完,gogogo。
你了解过一些响应式设计的方法吗
在 React 的语境下,如果面试官问“响应式设计的方法”,你可以把回答分成 两层含义:
- CSS 级响应式(传统前端响应式设计)
让页面在不同设备、屏幕尺寸下自适应显示,保证良好的用户体验。
常用方法:
- 流式布局(Fluid Layout) :使用百分比或相对单位代替固定宽度
- 媒体查询(Media Queries) :根据屏幕宽度或设备特性调整样式,下一个题目就是关于这个。
- Flex 布局:自适应排列、换行
- Grid 布局:二维自适应栅格布局
- 相对单位:
em/rem/vw/vh等 - 响应式图片:
max-width: 100% - 移动优先设计(Mobile First) :从小屏设计,逐步增强大屏布局 可以和相对单位结合起来讲,再衍生到去除双击放大:user-scalable=no,移动端字体适配:font-family: -apple-system, BlinkMacSystemFont...,最后可以讲组件库lib-flexible和postcss-pxtorem
- React 级响应式(数据驱动 UI) UI 会根据数据变化自动更新,无需手动操作 DOM,体现“响应式”概念。
常用方法:
- State / Props:组件状态或属性变化自动触发视图更新
- Hooks:如
useState,useReducer管理状态,实现响应式效果 - 自定义 Hooks / 状态管理库:如
useStore或 Redux,使数据变化驱动 UI - 响应式布局库:结合 CSS 或 UI 组件库(如 AntD Grid / Flex)实现布局自适应
媒体查询
媒体查询(Media Query) 是 CSS3 提供的一种功能,允许根据设备的不同特性(如屏幕宽度、高度、分辨率、方向等)应用不同的样式,从而实现响应式设计。
👉 简单理解: “条件判断 + 样式规则” ,不同设备满足不同条件时会加载不同的 CSS。
@media mediatype and (condition) {
/* 样式 */
}
-
mediatype:媒体类型,例如:all:所有设备(默认)screen:屏幕print:打印机
-
(condition):条件表达式,例如:min-width:最小宽度max-width:最大宽度orientation:方向(portrait 竖屏 / landscape 横屏)resolution:分辨率
-
常用条件写法
- 按屏幕宽度
/* 手机(最大宽度 600px) */
@media screen and (max-width: 600px) {
body {
background: lightblue;
}
}
/* 平板(宽度 601px ~ 1024px) */
@media screen and (min-width: 601px) and (max-width: 1024px) {
body {
background: lightgreen;
}
}
/* PC(大于 1024px) */
@media screen and (min-width: 1025px) {
body {
background: lightyellow;
}
}
- 按方向
/* 竖屏 */
@media screen and (orientation: portrait) {
body {
font-size: 14px;
}
}
/* 横屏 */
@media screen and (orientation: landscape) {
body {
font-size: 18px;
}
}
- 按分辨率
/* 针对高清屏幕(Retina) */
@media screen and (min-resolution: 2dppx) {
img {
content: url("image@2x.png");
}
}
面试回答示例
媒体查询是 CSS3 提供的一种根据设备特性(比如宽度、高度、分辨率、方向等)应用不同样式的技术,是响应式设计的核心手段。
常见写法是基于屏幕宽度的 min-width 和 max-width,比如移动端小于 600px 用一套样式,PC 大于 1024px 用另一套样式。
它的优点是性能好、原生支持,缺点是规则维护复杂。
可以顺势讲出tailwindcss,可以自适应设备样式。
git 方面的命令以及考点
Git 基本命令
- 初始化和配置
git clone # 克隆远程仓库
git init # 初始化仓库
git config --global user.name "你的名字"
git config --global user.email "你的邮箱"
其中要注意
git config --global user.name "你的名字"
git config --global user.email "你的邮箱"
是 Git 配置用户信息 的核心命令,用于标识是谁在操作仓库。毕竟入职可能第一件事就是配置这个(●'◡'●)。
- 查看状态和历史
git status # 查看当前状态
git log --oneline # 查看提交历史
- 文件操作
git add file.txt # 将文件添加到暂存区
git commit -m "说明" # 提交到本地仓库
- 分支操作
git branch # 查看分支
git branch dev # 创建分支 dev
git checkout dev # 切换dev分支
git checkout -b dev # 创建并切换到 dev
git merge dev # 合并分支(当前分支和dev分支合并)
git branch -d dev # 删除dev分支
- 远程操作
git remote add origin url # 添加远程仓库
git remote -v # 查看远程仓库
git push origin main # 推送到远程
git pull origin main # 拉取远程更新并合并
git fetch origin # 获取远程更新(不合并)
- 回退与撤销
git reset file.txt # 清空单个文件的暂存
git reset # 清空所有文件的暂存
git reset --soft HEAD^ # 回退到上一个提交(修改内容保留在暂存区)
git reset --mixed HEAD^ # 回退到上一个提交(修改退回到工作区)
git reset --hard HEAD^ # 修改和暂存的内容都丢弃
git reset --hard <commit_id> # 回退到指定 commit,可以不用hard,用soft,mixed都行
git revert <commit_id> # 安全回退,历史不会丢失,适合多人协作
Git 常考点
- Git 工作区、暂存区、版本库
- 工作区(Working Directory) :写代码的地方
- 暂存区(Staging Area) :保存即将提交的快照
- 版本库(Repository) :真正存储历史的地方
常见问题:git add 是把改动从工作区放到暂存区,git commit 是把暂存区的内容提交到版本库。
-
Git reset vs revert
reset:直接修改历史,可能导致冲突,不推荐在共享分支使用revert:生成一个新的提交,抵消之前的提交,更安全
-
merge vs rebase
merge:保留历史分叉,生成一个合并节点(多一条分支记录)rebase:把提交“搬运”到目标分支上,历史更干净,但容易改写历史
-
pull vs fetch
git fetch:只下载远程最新内容,本地不变git pull:等于fetch + merge,会合并到本地
-
HEAD、HEAD^、HEAD~3
HEAD:当前最新提交HEAD^:上一个提交HEAD~3:往上数第 3 个提交
常见场景题
-
撤销一次提交但保留代码
→git reset --soft HEAD^ -
本地误删文件,想恢复
→git checkout -- file.txt注意: checkout 既能切换分支,又能恢复文件,这其实是git的历史遗留问题。
从 Git 2.23 开始,Git 官方把
checkout拆成了两个更清晰的命令:git switch→ 专门用于切换分支git restore→ 专门用于恢复文件
-
代码写一半临时切分支
→git stash保存,切分支,git stash pop恢复 -
在团队中你和团队的其他一个小伙伴同时修改了一个代码文件,直接push可能提示冲突,怎么解决
→ 这里就讲其中的一种方法。先拉取远程最新代码
git pull origin main
- 如果没有冲突,Git 会自动合并,然后你再 git push 就行。
- 如果有冲突,Git 会在文件中标记冲突部分
<<<<<<< HEAD
// 你的修改
=======
// 同事的修改
>>>>>>> origin/main
手动解决冲突
- 编辑文件,把
<<<<<<<、=======、>>>>>>>这些标记去掉 - 保留你想要的正确代码(可能是保留一方,也可能是合并两边逻辑)
标记冲突已解决并提交
git add app.js
git commit -m "fix: 修复在app.js中的冲突"
再推送到远程仓库
git push origin main
恭喜你,看完了。面试加油呀