中级前端面试题目全面总结

443 阅读8分钟

前言

前端开发领域日新月异,技术栈不断演进。本文旨在为准备中级前端开发岗位面试的候选人提供一份全面的知识总结,涵盖主流前端框架、JavaScript/TypeScript核心概念以及浏览器相关的重要知识点。无论您是正在准备面试,还是希望系统梳理前端知识体系,这篇文章都将为您提供有价值的参考。

一、前端框架篇

1. React核心概念

Q1: React虚拟DOM的工作原理是什么?​

虚拟DOM是React的核心概念之一,它是一个轻量级的JavaScript对象,是真实DOM的抽象表示。工作流程包括:

  1. 当组件状态变化时,React会创建新的虚拟DOM树
  2. 使用Diff算法比较新旧虚拟DOM树的差异
  3. 计算出最小变更集,批量更新真实DOM

优势​:减少直接操作DOM的性能开销,实现高效的界面更新。

Q2: React Hooks解决了哪些问题?常用Hooks有哪些?​

Hooks解决了类组件存在的几个问题:

  • 状态逻辑难以复用(render props/HOC带来的嵌套问题)
  • 复杂组件难以理解(生命周期中分散的逻辑)
  • 类组件学习成本高(this指向问题)

常用Hooks:

  • useState: 管理组件状态
  • useEffect: 处理副作用(替代生命周期)
  • useContext: 访问Context
  • useReducer: 复杂状态管理
  • useCallback/useMemo: 性能优化
  • useRef: 访问DOM或保存可变值

2. Vue核心概念

Q3: Vue2和Vue3的主要区别有哪些?​

  1. 响应式系统​:

    • Vue2使用Object.defineProperty
    • Vue3使用Proxy,支持更多数据类型和更好的性能
  2. 组合式API​:

    • Vue3引入setup函数和组合式API,逻辑组织更灵活
  3. 性能优化​:

    • Vue3的虚拟DOM重写,支持静态提升等优化
    • 更小的包体积(Tree-shaking支持)
  4. TypeScript支持​:

    • Vue3提供更好的TS类型支持
  5. 生命周期变化​:

    • beforeCreatecreatedsetup替代
    • 其他生命周期添加on前缀(如onMounted

Q4: Vue的响应式原理如何实现?​

Vue2实现:

  1. 通过Object.defineProperty劫持数据属性的getter/setter
  2. 每个组件实例对应一个Watcher实例
  3. 依赖收集:getter中收集依赖(Watcher)
  4. 派发更新:setter中通知依赖更新

Vue3实现:

  1. 使用Proxy代理整个对象
  2. 通过tracktrigger函数实现依赖收集和派发更新
  3. 支持更多数据类型(如Map、Set等)

3. 框架对比与选型

Q5: React和Vue的主要区别是什么?​

方面ReactVue
设计理念函数式编程,单向数据流渐进式框架,双向绑定
模板语法JSX基于HTML的模板语法
状态管理需要配合Redux/MobX等内置Vuex/Pinia
学习曲线较高(需理解函数式概念)较低(更接近传统Web开发)
灵活性更高(可搭配多种库)更约定俗成
性能虚拟DOM优化虚拟DOM+响应式系统优化
社区生态更庞大增长迅速

二、JavaScript核心篇

1. 作用域与闭包

Q6: 解释JavaScript中的作用域链和闭包

作用域链:

  • 函数执行时会创建执行上下文,包含变量对象、作用域链和this
  • 作用域链是变量对象的链表,用于标识符解析
  • 内部函数可以访问外部函数的作用域

闭包:

  • 函数可以记住并访问所在的词法作用域,即使函数在当前作用域外执行
  • 常见应用:模块模式、私有变量、函数工厂、高阶函数等
function createCounter() {
  let count = 0;
  return function() {
    return ++count;
  };
}

const counter = createCounter();
console.log(counter()); // 1
console.log(counter()); // 2

2. 异步编程

Q7: 解释Event Loop和异步执行机制

JavaScript是单线程语言,通过Event Loop实现异步:

  1. 调用栈​:同步代码按顺序执行

  2. 任务队列​:

    • 宏任务队列:setTimeout、setInterval、I/O等
    • 微任务队列:Promise.then、MutationObserver等
  3. 执行顺序​:

    • 执行同步代码(调用栈)
    • 执行当前所有微任务
    • 执行一个宏任务
    • 重复上述过程
console.log('1');

setTimeout(() => console.log('2'), 0);

Promise.resolve().then(() => console.log('3'));

console.log('4');
// 输出顺序:1, 4, 3, 2

3. 原型与继承

Q8: 解释JavaScript的原型链继承

  1. 每个对象都有__proto__属性指向其构造函数的prototype
  2. 访问对象属性时,会沿着原型链向上查找
  3. 原型链的终点是Object.prototype.__proto__(null)
function Person(name) {
  this.name = name;
}
Person.prototype.sayName = function() {
  console.log(this.name);
};

function Student(name, grade) {
  Person.call(this, name);
  this.grade = grade;
}
Student.prototype = Object.create(Person.prototype);
Student.prototype.constructor = Student;

const s = new Student('Tom', 5);
s.sayName(); // Tom

ES6引入class语法糖,底层仍是基于原型的继承。

4. ES6+新特性

Q9: 列举并解释常用的ES6+特性

  1. let/const​:块级作用域变量声明
  2. 箭头函数​:简洁语法,不绑定this
  3. 模板字符串​:支持多行和插值
  4. 解构赋值​:从数组/对象中提取值
  5. 默认参数​:函数参数默认值
  6. 展开/剩余运算符​:...操作符
  7. Promise​:更好的异步处理
  8. 模块化​:import/export
  9. 类语法​:class关键字
  10. Symbol​:唯一值
  11. Map/Set​:新的数据结构
  12. Proxy/Reflect​:元编程
  13. 可选链(?.)​​:安全访问嵌套属性
  14. 空值合并(??)​​:提供默认值
  15. async/await​:同步风格写异步代码

三、TypeScript篇

1. 基础概念

Q10: TypeScript相比JavaScript有哪些优势?​

  1. 静态类型检查​:编译时发现类型错误
  2. 更好的代码提示​:IDE支持更完善
  3. 代码可维护性​:大型项目更易维护
  4. 渐进式采用​:可逐步迁移
  5. 现代JavaScript支持​:支持最新ECMAScript特性
  6. 丰富的类型系统​:接口、泛型、联合类型等
  7. 更好的重构能力​:类型信息支持安全重构

2. 核心特性

Q11: 解释TypeScript中的接口和类型别名的区别

特性接口(interface)类型别名(type)
扩展方式使用extends继承使用&交叉类型
合并声明支持同名接口自动合并不支持
实现类可以被类实现(implements)不能直接被类实现
原始类型只能描述对象类型可以描述任意类型
性能更适合声明形状复杂类型计算可能影响性能
// 接口
interface Person {
  name: string;
}
interface Employee extends Person {
  salary: number;
}

// 类型别名
type Person = {
  name: string;
};
type Employee = Person & { salary: number };

3. 高级类型

Q12: 解释TypeScript中的泛型及其应用场景

泛型允许创建可重用的组件,这些组件可以支持多种类型:

function identity<T>(arg: T): T {
  return arg;
}

// 使用
const output = identity<string>("hello");
const output2 = identity("hello"); // 类型推断

应用场景:

  1. 函数/方法​:创建类型安全的工具函数
  2. ​:创建可重用的数据结构(如集合)
  3. 接口​:定义灵活的形状
  4. 约束类型​:使用extends约束泛型范围
interface Lengthwise {
  length: number;
}

function loggingIdentity<T extends Lengthwise>(arg: T): T {
  console.log(arg.length);
  return arg;
}

四、浏览器相关篇

1. 渲染原理

Q13: 描述浏览器渲染页面的过程

  1. 解析HTML​:构建DOM树
  2. 解析CSS​:构建CSSOM树
  3. 合并DOM和CSSOM​:形成渲染树(Render Tree)
  4. 布局(Layout)​​:计算元素的位置和大小
  5. 绘制(Paint)​​:将渲染树转换为屏幕上的像素
  6. 合成(Composite)​​:将各层合并显示

关键点​:

  • 重排(Reflow):布局改变(影响性能)
  • 重绘(Repaint):外观改变不影响布局
  • 优化:减少DOM操作,使用transform/opacity等属性(触发合成层)

2. 性能优化

Q14: 前端性能优化有哪些常用手段?​

  1. 资源优化​:

    • 压缩代码和资源
    • 使用CDN
    • 图片优化(WebP、懒加载)
    • 代码分割和按需加载
  2. 渲染优化​:

    • 减少重排重绘
    • 使用requestAnimationFrame
    • 虚拟列表优化长列表
    • 避免布局抖动
  3. 缓存策略​:

    • 合理设置HTTP缓存头
    • Service Worker缓存
    • 数据缓存(内存、localStorage)
  4. 网络优化​:

    • HTTP/2
    • 预加载/prefetch
    • 减少请求数量(雪碧图、字体图标)
  5. 代码优化​:

    • 防抖节流
    • Web Worker处理耗时任务
    • 避免内存泄漏

3. 安全相关

Q15: 常见的前端安全问题和防御措施

  1. XSS(跨站脚本攻击)​​:

    • 防御:输入输出编码,CSP策略,HttpOnly Cookie
  2. CSRF(跨站请求伪造)​​:

    • 防御:SameSite Cookie,CSRF Token,验证Referer
  3. 点击劫持​:

    • 防御:X-Frame-Options,Frame Busting代码
  4. 中间人攻击​:

    • 防御:HTTPS,HSTS
  5. 信息泄露​:

    • 防御:避免敏感信息在前端处理,设置安全头

五、综合实战题

Q16: 如何设计一个前端权限控制系统?​

  1. 路由权限​:

    • 定义路由元信息(meta)包含权限要求
    • 路由守卫检查用户权限
    • 动态生成菜单和路由表
  2. 组件权限​:

    • 创建权限指令(v-permission)
    • 高阶组件包裹需要权限控制的组件
  3. API权限​:

    • 请求拦截器检查权限
    • 后端同时验证
  4. 数据权限​:

    • 根据权限过滤返回数据
    • 前端处理UI展示逻辑
  5. 存储方案​:

    • JWT存储权限信息
    • 合理设置token过期时间

示例代码​:

// 路由守卫
router.beforeEach((to, from, next) => {
  const requiredRoles = to.meta.roles;
  if (!requiredRoles) return next();
  
  const userRoles = store.getters.roles;
  if (hasPermission(requiredRoles, userRoles)) {
    next();
  } else {
    next('/403');
  }
});

// 权限指令
Vue.directive('permission', {
  inserted(el, binding, vnode) {
    const { value } = binding;
    const roles = store.getters.roles;
    
    if (value && !hasPermission(value, roles)) {
      el.parentNode && el.parentNode.removeChild(el);
    }
  }
});

六、面试技巧与准备建议

  1. 理解原理而非死记硬背​:面试官更关注你对概念的理解深度
  2. 准备项目案例​:能够详细解释你做过的项目和技术选型
  3. 练习编码题​:LeetCode、Codewars等平台保持手感
  4. 了解公司技术栈​:针对性地准备相关框架知识
  5. 准备问题提问​:展示你对职位和技术的兴趣
  6. 模拟面试​:找朋友或使用在线平台进行模拟练习