前言
大家好,我是木斯佳。
相信很多人都感受到了,在AI浪潮的席卷之下,前端领域的门槛在变高,纯粹的"增删改查"岗位正在肉眼可见地减少。曾经热闹非凡的面经分享,如今也沉寂了许多。但我们都知道,市场的潮水退去,留下的才是真正在踏实准备、努力沉淀的人。学习的需求,从未消失,只是变得更加务实和深入。
这个专栏的初衷很简单:拒绝过时的、流水线式的PDF引流贴,专注于收集和整理当下最新、最真实的前端面试资料。我会在每一份面经和八股文的基础上,尝试从面试官的角度去拆解问题背后的逻辑,而不仅仅是提供一份静态的背诵答案。无论你是校招还是社招,目标是中大厂还是新兴团队,只要是真实发生、有价值的面试经历,我都会在这个专栏里为你沉淀下来。

温馨提示:市面上的面经鱼龙混杂,甄别真伪、把握时效,是我们对抗内卷最有效的武器。
面经原文内容(节选)
📍面试公司:X transfer
🕐面试时间:近期,用户上传于03-10
💻面试岗位:前端开发工程师
❓面试问题(仅作答4、5、7、8):
4. 八股
- == 和 ===的区别
- 怎么判断一个对象的类型 typeof/instanceof有什么区别
- setTimeout设置delay1秒,一定会1s后执行吗?
- js单线程怎么执行异步任务
- 闭包是什么,平时怎么用闭包
- es6语法糖有哪些,讲一下
- promise异常应该怎么捕获
- promise变成同步写法,(async/await)怎么捕获异常?
- 可以把promise的异常直接放在try/catch中捕获吗
- react常用的hooks,分别讲解
- 组件卸载时怎么清除定时器
- 用过rn吗
- 操作系统:内核态和用户态,进程通信的方式,计算机是怎么进行内存寻址的
5. 场景题: 一个客户端到客户端的网络请求很慢,后端排查没问题,前端该如何排查问题出现在哪一层,是哪个阶段慢。
7. mcp和skills分别是什么,平时怎么用
8. 手撕:合并两个有序链表
📝 X transfer前端一面·深度解析(节选)
🎯 面试整体画像
| 维度 | 特征 |
|---|---|
| 公司定位 | X transfer - 跨境支付/金融科技 |
| 面试风格 | 基础扎实型 + 场景排查型 + 前沿技术型 |
| 难度评级 | ⭐⭐⭐(三星,基础+场景+前沿) |
| 考察重心 | JS基础、异步编程、React、网络排查、AI概念、算法 |
木木有话说:X transfer面试相对难度不大,收录的原因是整体的面试题比较经典,适合多刷,另外,打好基本功的基础上可以多看一些场景化的题,因为实际直接考八股的还是比较少,很多面试官习惯从项目中去深挖知识点。
🔍 逐题深度解析
四、八股题集(JS基础核心)
问题: == 和===的区别
javascript
// == 允许类型转换,=== 不允许
console.log(1 == '1') // true(字符串转数字)
console.log(1 === '1') // false(类型不同)
// == 转换规则
// - 数字和字符串:字符串转数字
// - 布尔值和其他:布尔值转数字
// - null和undefined:相等,不转其他
console.log(null == undefined) // true
console.log(null == 0) // false
// 实际开发中,推荐使用 ===
问题:怎么判断一个对象的类型?typeof/instanceof有什么区别?
javascript
// typeof 适合基本类型
typeof 123 // 'number'
typeof 'abc' // 'string'
typeof true // 'boolean'
typeof undefined // 'undefined'
typeof Symbol() // 'symbol'
// typeof 对引用类型不够精确
typeof {} // 'object'
typeof [] // 'object'(数组也是object)
typeof null // 'object'(历史遗留bug)
// instanceof 适合判断具体对象类型
[] instanceof Array // true
{} instanceof Object // true
new Date() instanceof Date // true
// instanceof 检查原型链
class Parent {}
class Child extends Parent {}
const obj = new Child()
obj instanceof Child // true
obj instanceof Parent // true
// 万能方法:Object.prototype.toString
Object.prototype.toString.call([]) // '[object Array]'
Object.prototype.toString.call(null) // '[object Null]'
Object.prototype.toString.call(new Date) // '[object Date]'
问题:setTimeout设置delay1秒,一定会1s后执行吗?
javascript
// 不一定,setTimeout是宏任务,需要等待执行栈清空
console.log('start')
setTimeout(() => {
console.log('timeout')
}, 1000)
// 假设这里有大量同步任务阻塞
for(let i = 0; i < 1000000000; i++) {} // 耗时>1s
console.log('end')
// 输出顺序:start -> end -> timeout
// timeout的实际执行时间 = 1s + 阻塞时间
// 最小延迟:4ms(嵌套调用时)
setTimeout(() => {}, 0) // 实际可能4ms后执行
// 结论:setTimeout保证的是最小延迟,不是精确执行时间
问题:js单线程怎么执行异步任务?
javascript
// 通过事件循环(Event Loop)
// 1. 调用栈执行同步任务
// 2. 异步任务交给Web API处理
// 3. 任务完成后回调放入任务队列
// 4. 调用栈清空后,从任务队列取回调执行
console.log(1)
setTimeout(() => {
console.log(2) // 宏任务
}, 0)
Promise.resolve().then(() => {
console.log(3) // 微任务
})
console.log(4)
// 执行流程:
// 同步:1,4 → 微任务:3 → 宏任务:2
// 输出:1,4,3,2
// 宏任务:setTimeout、setInterval、I/O
// 微任务:Promise.then、MutationObserver
问题:闭包是什么,平时怎么用闭包?
javascript
// 闭包:函数 + 词法环境的引用
function createCounter() {
let count = 0 // 被内部函数引用
return function() {
count++ // 内部函数引用外部变量
return count
}
}
const counter = createCounter()
console.log(counter()) // 1
console.log(counter()) // 2
// 应用场景
// 1. 私有变量
function createUser(name) {
let _name = name
return {
getName: () => _name,
setName: (newName) => { _name = newName }
}
}
// 2. 防抖节流
function debounce(fn, delay) {
let timer
return function(...args) {
clearTimeout(timer)
timer = setTimeout(() => fn.apply(this, args), delay)
}
}
// 3. 模块化
const module = (function() {
let privateVar = 0
function privateFn() {}
return {
publicFn: () => { privateVar++ }
}
})()
// 4. 注意内存泄漏
// 闭包会保留外部变量,用完后及时释放
问题:es6语法糖有哪些?
javascript
// 1. 箭头函数
const add = (a, b) => a + b
// 2. 模板字符串
const name = 'Tom'
const str = `Hello ${name}`
// 3. 解构赋值
const { name, age } = user
const [first, second] = arr
// 4. 展开运算符
const newArr = [...arr, 4]
const newObj = { ...obj, a: 1 }
// 5. 类语法
class Person {
constructor(name) { this.name = name }
say() {}
}
// 6. 模块化
import { add } from './math'
export default {}
// 7. 对象属性简写
const name = 'Tom'
const obj = { name } // 相当于 { name: name }
// 8. 可选链操作符
const city = user?.address?.city
// 9. 空值合并
const count = data ?? 0
问题:promise异常应该怎么捕获?
javascript
// 1. catch方法
fetch('/api/data')
.then(res => res.json())
.then(data => console.log(data))
.catch(err => console.error('捕获异常:', err))
// 2. then的第二个参数
fetch('/api/data')
.then(
res => res.json(),
err => console.error('请求失败:', err)
)
// 注意:then的第二个参数捕获不到第一个回调中的异常
问题:promise变成同步写法,(async/await)怎么捕获异常?
javascript
// 1. try/catch
async function fetchData() {
try {
const response = await fetch('/api/data')
const data = await response.json()
console.log(data)
} catch (err) {
console.error('捕获异常:', err)
}
}
// 2. 多个await可以放在同一个try/catch
async function fetchAll() {
try {
const user = await fetchUser()
const posts = await fetchPosts(user.id)
const comments = await fetchComments(posts[0].id)
return { user, posts, comments }
} catch (err) {
console.error('任意一个失败都会进入这里')
}
}
问题:可以把promise的异常直接放在try/catch中捕获吗?
javascript
// 直接放在try/catch中捕获不到
try {
fetch('/api/data').then(res => res.json())
} catch (err) {
// 这里的catch捕获不到fetch的异常
}
// 原因:try/catch只能捕获同步代码的异常
// fetch是异步的,已经离开了try块
// 正确做法
fetch('/api/data')
.then(res => res.json())
.catch(err => console.log(err))
// 或使用async/await
try {
const res = await fetch('/api/data')
const data = await res.json()
} catch (err) {
console.log(err)
}
问题:react常用的hooks,分别讲解
javascript
// 1. useState - 状态管理
const [count, setCount] = useState(0)
// 2. useEffect - 副作用
useEffect(() => {
document.title = `点击了${count}次`
return () => { /* 清理 */ }
}, [count])
// 3. useContext - 上下文
const theme = useContext(ThemeContext)
// 4. useReducer - 复杂状态
const [state, dispatch] = useReducer(reducer, initialState)
// 5. useCallback - 缓存函数
const handleClick = useCallback(() => {
doSomething(count)
}, [count])
// 6. useMemo - 缓存计算结果
const expensiveValue = useMemo(() => {
return computeExpensive(count)
}, [count])
// 7. useRef - 引用
const inputRef = useRef(null)
useEffect(() => { inputRef.current.focus() }, [])
// 8. useLayoutEffect - 同步执行
useLayoutEffect(() => {
// DOM更新后同步执行
}, [])
问题:组件卸载时怎么清除定时器?
javascript
// 1. 在useEffect的清理函数中
function Timer() {
useEffect(() => {
const timer = setInterval(() => {
console.log('tick')
}, 1000)
// 返回清理函数,组件卸载时执行
return () => {
clearInterval(timer)
console.log('定时器已清理')
}
}, []) // 空依赖,只执行一次
return <div>Timer</div>
}
// 2. 使用useRef存储定时器ID
function Timer() {
const timerRef = useRef()
useEffect(() => {
timerRef.current = setInterval(() => {
console.log('tick')
}, 1000)
return () => {
clearInterval(timerRef.current)
}
}, [])
return <div>Timer</div>
}
// 3. 自定义Hook封装
function useInterval(callback, delay) {
useEffect(() => {
const timer = setInterval(callback, delay)
return () => clearInterval(timer)
}, [callback, delay])
}
五、网络排查场景题
问题:客户端到客户端的网络请求很慢,后端排查没问题,前端该如何排查问题出现在哪一层,是哪个阶段慢?
javascript
// 前端排查步骤
// 1. 使用浏览器DevTools的Network面板
// - 查看请求时间线
// - 分析各阶段耗时
// 2. 请求阶段分析
// - DNS查询:dns时间
// - TCP连接:connect时间
// - TLS握手:ssl时间
// - 发送请求:request时间
// - 等待响应:waiting时间
// - 接收数据:download时间
// 3. 对比多次请求
// - 是否每次都慢
// - 特定网络下慢(WiFi/4G)
// - 特定时段慢
// 4. 使用Performance API
const start = performance.now()
await fetch('/api/data')
const end = performance.now()
console.log(`请求耗时: ${end - start}ms`)
// 5. Resource Timing API
const [entry] = performance.getEntriesByType('resource')
console.log({
dns: entry.domainLookupEnd - entry.domainLookupStart,
tcp: entry.connectEnd - entry.connectStart,
ssl: entry.secureConnectionStart ? entry.connectEnd - entry.secureConnectionStart : 0,
waiting: entry.responseStart - entry.requestStart,
download: entry.responseEnd - entry.responseStart
})
// 6. 排查网络层
// - 客户端网络环境
// - 代理/VPN
// - 防火墙
// 7. 排查应用层
// - 请求体大小
// - 响应体大小
// - 数据格式
// 8. 工具链
// - Chrome DevTools
// - Charles/Fiddler抓包
// - Wireshark(底层网络分析)
七、mcp和skills
问题:mcp和skills分别是什么,平时怎么用?
javascript
// 1. MCP (Model Context Protocol)
// 模型上下文协议,由Anthropic提出
// MCP的作用:
// - 为AI模型提供标准化的上下文管理
// - 支持工具调用、资源访问
// - 维护多轮对话状态
// MCP工作流程
interface MCPRequest {
context: {
sessionId: string,
history: Message[],
tools: Tool[]
},
query: string
}
// 2. Skills(AI技能/函数调用)
// AI模型可以调用的外部功能
// Skill定义
interface Skill {
name: string,
description: string,
parameters: {
type: 'object',
properties: Record<string, any>,
required: string[]
},
execute: (params: any) => Promise<any>
}
// 实际示例:天气查询Skill
const weatherSkill = {
name: 'get_weather',
description: '获取天气信息',
parameters: {
type: 'object',
properties: {
city: { type: 'string', description: '城市' }
},
required: ['city']
},
execute: async ({ city }) => {
return fetch(`/api/weather?city=${city}`).then(r => r.json())
}
}
// 3. 平时怎么用
// - 集成AI对话功能时配置MCP
// - 定义业务相关的Skills供AI调用
// - 维护对话上下文状态
// 4. 学习建议
// - 关注Anthropic/OpenAI的Function Calling
// - 实践AI应用开发
// - 了解LangChain等框架
八、手撕:合并两个有序链表
问题:合并两个有序链表
javascript
// 链表节点定义
function ListNode(val, next) {
this.val = (val === undefined ? 0 : val)
this.next = (next === undefined ? null : next)
}
// 1. 迭代法
function mergeTwoLists(list1, list2) {
// 创建虚拟头节点
const dummy = new ListNode(-1)
let current = dummy
// 遍历两个链表
while (list1 && list2) {
if (list1.val <= list2.val) {
current.next = list1
list1 = list1.next
} else {
current.next = list2
list2 = list2.next
}
current = current.next
}
// 连接剩余部分
current.next = list1 || list2
return dummy.next
}
// 2. 递归法
function mergeTwoLists(list1, list2) {
// 递归终止条件
if (!list1) return list2
if (!list2) return list1
if (list1.val <= list2.val) {
list1.next = mergeTwoLists(list1.next, list2)
return list1
} else {
list2.next = mergeTwoLists(list1, list2.next)
return list2
}
}
// 3. 测试
const l1 = { val: 1, next: { val: 3, next: { val: 5, next: null } } }
const l2 = { val: 2, next: { val: 4, next: { val: 6, next: null } } }
const merged = mergeTwoLists(l1, l2)
// 输出:1→2→3→4→5→6
// 4. 复杂度分析
// 时间复杂度:O(n+m)
// 空间复杂度:迭代O(1),递归O(n+m)
📚 知识点速查表(节选)
| 知识点 | 核心要点 |
|---|---|
| == vs === | ==类型转换,===不转换 |
| 类型判断 | typeof(基本类型)、instanceof(原型链)、toString(万能) |
| setTimeout | 最小延迟,不保证精确 |
| 事件循环 | 同步→微任务→宏任务 |
| 闭包 | 函数+词法环境、私有变量、防抖节流 |
| ES6语法 | 箭头函数、模板字符串、解构、展开、类、模块 |
| Promise异常 | catch、then第二参数、async/await+try/catch |
| React Hooks | useState、useEffect、useCallback、useMemo |
| 清除定时器 | useEffect清理函数、useRef存储ID |
| 网络排查 | Network面板、Performance API、各阶段耗时 |
| MCP/Skills | 模型上下文协议、AI函数调用 |
| 合并链表 | 迭代法、递归法、虚拟头节点 |
📌 最后一句:
X transfer的这场面试,基础扎实、场景实用、前沿有深度。JS基础是开发者的内功,网络排查是实战必备,mcp/skills是AI时代的新要求。小伙伴们,我建议基本功扎实了可以多练习场景化思考的能力。