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

温馨提示:市面上的面经鱼龙混杂,甄别真伪、把握时效,是我们对抗内卷最有效的武器。
面经原文内容
📍面试公司:美团财务科技
🕐面试时间:4月9日上午11点,时长25分钟
💻面试岗位:前端日常一面
📝面试体验:人生第一次面试,面试官很友善,基本都是简单八股
❓面试问题:
- JS 的数据类型有几种
- 基础数据类型和引用数据类型的本质区别
- js 定义变量的方式有几种
- let 和 var 有什么区别
- promise 解决什么问题
- 箭头函数跟普通函数有什么区别
- ES6 向 ES5 的转换一般是怎么做的
- 用 webpack 多一些还是 Vite 多一些
- Vite 有哪些配置项你常用的
- Vue 父子组件传递参数该怎么传
- vue 3 里面做全局状态管理该一般是怎么做
- 学生管理系统从 0 到 1 技术选型,框架用 Vue 还是 react,打包工具用哪一个,UI 组件库用哪一个,说明理由
- 手撕:143. 重排链表
来源:牛客网 前端死了咩
💡 木木有话说(刷前先看)
美团这场日常实习一面,是一份非常标准的基础面经 。面试官友善,题目基础,没有深挖项目,可能是因为技术栈差异或日常实习门槛较低。问题覆盖JS基础、ES6、构建工具、Vue核心、技术选型,最后一道手撕链表题。对于第一次面试的同学来说,这份面经很有参考价值------基础扎实,就能从容应对。
📝 美团财务科技前端一面·深度解析
🎯 面试整体画像
| 维度 | 特征 |
|---|---|
| 面试风格 | 基础友好型 + 标准八股 + 无压力追问 |
| 难度评级 | ⭐⭐(二星,基础为主,适合新手) |
| 考察重心 | JS数据类型、ES6特性、构建工具、Vue核心、技术选型 |
| 特殊之处 | 日常实习门槛较低,偏重基础而非项目深度 |
🔍 逐题深度解析
二、JS的数据类型有几种
回答思路:最新ECMAScript标准有8种数据类型。
分类:
- 基础数据类型(7种) :
number、string、boolean、null、undefined、symbol(ES6)、bigint(ES2020) - 引用数据类型(1种) :
object(包含数组、函数、日期、正则等)
javascript
typeof 123 // 'number'
typeof 'str' // 'string'
typeof true // 'boolean'
typeof undefined // 'undefined'
typeof null // 'object'(历史遗留bug)
typeof Symbol() // 'symbol'
typeof 123n // 'bigint'
typeof {} // 'object'
typeof [] // 'object'
typeof function(){} // 'function'
三、基础数据类型和引用数据类型的本质区别
回答思路:从存储位置、赋值方式、比较方式三个维度说明。
| 维度 | 基础数据类型 | 引用数据类型 |
|---|---|---|
| 存储位置 | 栈内存(固定大小) | 堆内存(动态大小),栈存引用地址 |
| 赋值方式 | 值拷贝(独立副本) | 引用拷贝(指向同一对象) |
| 比较方式 | 值比较 | 引用地址比较 |
javascript
// 基础类型:值拷贝
let a = 10
let b = a
b = 20
console.log(a) // 10(不变)
// 引用类型:引用拷贝
let obj1 = { name: 'Tom' }
let obj2 = obj1
obj2.name = 'Jerry'
console.log(obj1.name) // 'Jerry'(被修改)
// 比较
10 === 10 // true
{ name: 'Tom' } === { name: 'Tom' } // false(不同对象)
四、js定义变量的方式有几种
回答思路 :ES6之前有var,ES6新增let和const。
| 方式 | 作用域 | 变量提升 | 重复声明 | 可修改 |
|---|---|---|---|---|
var |
函数作用域 | 是(undefined) | 允许 | 是 |
let |
块级作用域 | 否(TDZ) | 不允许 | 是 |
const |
块级作用域 | 否(TDZ) | 不允许 | 否(属性可改) |
javascript
var a = 1
let b = 2
const c = 3
// const声明的对象属性可以修改
const obj = { name: 'Tom' }
obj.name = 'Jerry' // 允许
五、let和var有什么区别
回答思路:从作用域、变量提升、重复声明、全局属性四个角度回答。
区别:
- 作用域 :
var函数作用域,let块级作用域({}内) - 变量提升 :
var提升但值为undefined,let提升但存在暂时性死区(TDZ) - 重复声明 :
var允许重复声明,let不允许 - 全局声明 :
var在全局声明会成为window属性,let不会
javascript
// 块级作用域
{
var a = 1
let b = 2
}
console.log(a) // 1
console.log(b) // ReferenceError
// 暂时性死区
console.log(x) // undefined(var提升)
var x = 1
console.log(y) // ReferenceError(TDZ)
let y = 2
六、promise解决什么问题
回答思路:Promise是异步编程的解决方案。
解决的问题:
- 回调地狱:避免多层嵌套的回调函数
- 错误处理 :统一的
.catch()捕获异步错误 - 并发控制 :
Promise.all、Promise.race等处理多个异步操作
javascript
// 回调地狱
getData(function(a) {
getMoreData(a, function(b) {
getMoreData(b, function(c) {
console.log(c)
})
})
})
// Promise链式调用
getData()
.then(a => getMoreData(a))
.then(b => getMoreData(b))
.then(c => console.log(c))
.catch(err => console.error(err))
七、箭头函数跟普通函数的区别
回答思路 :从this绑定、arguments、构造函数、prototype等角度回答。
| 特性 | 普通函数 | 箭头函数 |
|---|---|---|
this |
动态绑定(调用时决定) | 静态绑定(定义时继承外层) |
arguments |
有 | 无(可用rest参数替代) |
| 构造函数 | 可以(new调用) |
不可以(会报错) |
prototype |
有 | 无 |
| 简写 | 无 | 单参数可省略括号,单语句可省略return |
javascript
// this指向
const obj = {
name: 'Tom',
normalFn: function() {
console.log(this.name) // Tom(调用时指向obj)
},
arrowFn: () => {
console.log(this.name) // undefined(继承外层,通常是window)
}
}
// 不能作为构造函数
const Fn = () => {}
const f = new Fn() // TypeError
八、ES6向ES5的转换一般是怎么做的
回答思路 :使用Babel进行转译。
流程:
- 解析(Parse):将ES6代码解析成AST(抽象语法树)
- 转换(Transform):将ES6语法对应的AST节点转换为ES5节点
- 生成(Generate):将转换后的AST生成ES5代码
核心插件 :@babel/preset-env,根据目标浏览器环境自动决定转换哪些特性。
javascript
// 配置示例(.babelrc)
{
"presets": [
["@babel/preset-env", {
"targets": "> 0.25%, not dead"
}]
]
}
常见转换:
const/let→var- 箭头函数 → 普通函数
- 模板字符串 → 字符串拼接
class→ 构造函数 + 原型方法
九、用webpack多一些还是Vite多一些
回答思路:根据项目类型选择。
回答示例 :
"我平时用Vite 多一些,因为它开发环境启动快、热更新快。但在一些需要精细控制打包配置的老项目或复杂项目中,也会用到Webpack。"
十、Vite有哪些配置项你常用的
回答思路:列举常用配置。
javascript
// vite.config.js
export default {
// 插件
plugins: [vue(), react()],
// 路径别名
resolve: {
alias: {
'@': '/src'
}
},
// 开发服务器
server: {
port: 3000,
proxy: {
'/api': 'http://localhost:8080'
}
},
// 构建配置
build: {
outDir: 'dist',
sourcemap: true,
rollupOptions: {
external: ['react']
}
},
// CSS预处理器
css: {
preprocessorOptions: {
scss: { additionalData: `@import "@/styles/variables.scss";` }
}
}
}
十一、Vue父子组件传递参数
回答思路 :父传子用props,子传父用emit。
父传子:
vue
<!-- 父组件 -->
<template>
<Child :message="parentMsg" />
</template>
<script setup>
import Child from './Child.vue'
const parentMsg = 'Hello from parent'
</script>
<!-- 子组件 -->
<script setup>
const props = defineProps(['message'])
console.log(props.message)
</script>
子传父:
vue
<!-- 子组件 -->
<script setup>
const emit = defineEmits(['update'])
emit('update', 'data from child')
</script>
<!-- 父组件 -->
<template>
<Child @update="handleUpdate" />
</template>
<script setup>
const handleUpdate = (data) => {
console.log(data)
}
</script>
十二、Vue3全局状态管理
回答思路 :Vue3推荐使用Pinia(官方状态管理库)。
Pinia特点:
- 轻量、TypeScript友好
- 去掉了mutations(只有state、getters、actions)
- 支持Vue DevTools
javascript
// stores/user.js
import { defineStore } from 'pinia'
export const useUserStore = defineStore('user', {
state: () => ({
name: 'Tom',
age: 18
}),
getters: {
doubleAge: (state) => state.age * 2
},
actions: {
updateName(newName) {
this.name = newName
}
}
})
// 组件中使用
import { useUserStore } from '@/stores/user'
const userStore = useUserStore()
console.log(userStore.name)
userStore.updateName('Jerry')
十三、学生管理系统技术选型
回答思路:说明选型理由,展现思考过程。
框架 :选择Vue(因为熟悉,上手快;React也很优秀,但团队倾向Vue)
打包工具 :选择Vite(开发环境启动快,热更新体验好,适合中小型项目)
UI组件库:
- Element Plus:Vue3生态最成熟的桌面端组件库,适合后台管理系统
- Ant Design Vue:设计规范统一,但体积略大
- Naive UI:TypeScript友好,但生态较新
推荐:Element Plus + Vite + Vue3 + Pinia
二十、手撕:143. 重排链表
题目 :将链表 L0 → L1 → ... → Ln-1 → Ln 重排为 L0 → Ln → L1 → Ln-1 → L2 → Ln-2 → ...
解题思路:
- 找到链表中点(快慢指针)
- 反转后半部分链表
- 交替合并两个链表
javascript
function reorderList(head) {
if (!head || !head.next) return
// 1. 找中点
let slow = head, fast = head
while (fast.next && fast.next.next) {
slow = slow.next
fast = fast.next.next
}
// 2. 反转后半部分
let prev = null
let curr = slow.next
slow.next = null // 断开前后
while (curr) {
const next = curr.next
curr.next = prev
prev = curr
curr = next
}
// 3. 交替合并
let first = head
let second = prev
while (second) {
const next1 = first.next
const next2 = second.next
first.next = second
second.next = next1
first = next1
second = next2
}
}
时间复杂度 :O(n)
空间复杂度:O(1)
📚 知识点速查表
| 知识点 | 核心要点 |
|---|---|
| JS数据类型 | 7种基础(number/string/boolean/null/undefined/symbol/bigint)+ object |
| 基础vs引用 | 栈存值/堆存址、值拷贝/引用拷贝、值比较/地址比较 |
| 定义变量 | var(函数作用域)、let/const(块级作用域)、const不可重新赋值 |
| let vs var | 块级作用域、TDZ、不能重复声明、不挂载window |
| Promise | 解决回调地狱、统一错误处理、并发控制 |
| 箭头函数 | this静态绑定、无arguments、不能new、无prototype |
| ES6转ES5 | Babel解析→转换→生成,@babel/preset-env |
| Vite配置 | plugins、resolve.alias、server.proxy、build |
| Vue父子通信 | props(父→子)、emit(子→父) |
| 全局状态 | Pinia(state/getters/actions) |
| 技术选型 | Vue3 + Vite + Element Plus + Pinia |
| 重排链表 | 找中点→反转后半→交替合并 |
📌 最后一句:
美团这场日常一面,是一份"新手友好"的基础面经。题目虽简单,但覆盖了JS核心、ES6、构建工具、Vue基础等必备知识。对于第一次面试的同学来说,这样的面试有助于建立信心------只要基础扎实,就能从容应对。从用户反馈看,面试完当天下午就约了二面,说明表现不错。基础是前端的立身之本,把地基打牢,才能走得更远。