收集一点面试题。说实话我是感觉没啥用的大部分记住了以后就会忘记除非用的时候再想起,也是没办法。
大致的面试方向让GPT列了一下,用于对照有没有缺的:
路线表:
第一部分:前端基础(The Core Fundamentals)
1. JavaScript (重中之重)
核心概念:
- 数据类型:基本类型 vs 引用类型,
nullvsundefined,Symbol和BigInt。 - 类型转换:隐式转换规则(特别是
==和+),显式转换方法。 - 作用域 (Scope) 与作用域链:全局作用域、函数作用域、块级作用域 (
let/const)。 - 闭包 (Closure):是什么、为什么、应用场景(防抖、节流、模块化)、可能导致的内存泄漏。
this指向:不同场景下(全局、函数、对象方法、箭头函数、call/apply/bind)的this指向问题。- 原型 (Prototype) 与原型链:
__proto__、prototype、constructor的关系,继承的实现方式。 - 执行上下文 (Execution Context) 与调用栈 (Call Stack)。
- 数据类型:基本类型 vs 引用类型,
异步编程:
- 事件循环 (Event Loop):宏任务 (Macrotask) 与微任务 (Microtask) 的区别和执行顺序(非常高频的考点)。
- Promise:三种状态、
then/catch/finally,Promise.all/race/any的用法和区别。 async/await:语法糖的本质,如何处理错误(try...catch)。
ES6+ 新特性:
let/constvsvar的区别。- 箭头函数及其
this。 - 解构赋值、模板字符串、默认参数。
Map/SetvsObject/Array。- 模块化 (
import/export)。 Class语法糖。
手写代码题(高频):
- 防抖 (Debounce) 和节流 (Throttle)。
- 深拷贝 (Deep Clone)。
- 实现
call/apply/bind。 - 实现一个
Promise或Promise.all。 - 数组扁平化、去重。
- 实现一个事件发布/订阅模型 (Event Emitter)。
2. CSS (Cascading Style Sheets)
- 核心概念:
- 盒子模型 (Box Model):标准盒模型 vs IE 盒模型 (
box-sizing)。 - 选择器与优先级:
!important > 内联 > ID > 类/属性/伪类 > 标签 > 通配符。 - BFC (块级格式化上下文):是什么、触发条件、应用场景(清除浮动、防止 margin 塌陷)。
- 层叠上下文 (Stacking Context):
z-index的工作原理。
- 盒子模型 (Box Model):标准盒模型 vs IE 盒模型 (
- 布局 (Layout):
- Flexbox 布局:主轴、交叉轴、
flex-direction,justify-content,align-items,flex属性。 - Grid 布局:二维布局,
grid-template-columns/rows,grid-gap,grid-area。 - 定位 (Positioning):
static,relative,absolute,fixed,sticky的区别和用途。 - 浮动 (Float):以及如何清除浮动。
- Flexbox 布局:主轴、交叉轴、
- 进阶与工程化:
- CSS 动画:
transition和animation的区别。 - 预处理器:Sass/Less/Stylus(变量、Mixin、嵌套等)。
- CSS Modules / CSS-in-JS:解决 CSS 全局污染和作用域问题。
- 响应式设计:媒体查询 (
@media)。
- CSS 动画:
3. HTML (HyperText Markup Language)
- 语义化标签:
header,footer,nav,section,article,aside的使用场景,好处是什么(SEO、可访问性)。 - HTML5 新特性:
canvas,video,audio, 新的表单类型。 - DOCTYPE 的作用:触发标准模式。
- 可访问性 (Accessibility, a11y):
alt属性,aria-*属性的角色。 - SEO (搜索引擎优化):
title,meta标签的优化。
第二部分:框架与库 (Frameworks & Libraries)
通常要求至少精通一个主流框架。
- React / Vue (选择一个深入)
- 核心思想:声明式 UI、组件化、数据驱动视图。
- Virtual DOM:是什么,为什么需要它,Diff 算法(非常重要,需要理解其 key 的作用和 diff 过程)。
- 组件生命周期:创建、更新、销毁各个阶段的钩子函数。
- 组件通信:父子、子父、兄弟、跨级通信的各种方式。
- 状态管理:
- React:
useState,useReducer,Context API,以及 Redux / Zustand / MobX 的原理和使用。 - Vue:
props,$emit, EventBus, Vuex / Pinia 的原理和使用。
- React:
- React Hooks vs. Vue Composition API:它们的优势和解决了什么问题。
- 原理深挖:
- React: Fiber 架构、Scheduler、合成事件。
- Vue: 响应式原理(
Object.definePropertyvsProxy)。
第三部分:工程化与工具链 (Engineering & Tooling)
这部分体现你的工程能力和开发效率。
- 构建工具:
- Webpack:核心概念(Entry, Output, Loader, Plugin, Mode),工作流程,常见优化(代码分割、Tree Shaking、打包速度优化)。
- Vite:与 Webpack 的区别,为什么快(ESM、esbuild)。
- 包管理器:
npm/yarn/pnpm的区别,package.json和package-lock.json的作用。 - 代码规范与质量:ESLint (代码检查), Prettier (代码格式化), TypeScript (类型系统)。
- Git 版本控制:常用命令 (
mergevsrebase,cherry-pick,reset),分支管理策略 (Git Flow)。 - 前端测试:单元测试 (Jest/Vitest), E2E 测试 (Cypress/Playwright)。
第四部分:浏览器与网络 (Browser & Network)
这部分是高级和资深岗位的分水岭。
- 浏览器渲染原理:
- 关键渲染路径 (Critical Rendering Path):从输入 URL到页面展示的全过程(DNS 查询 -> TCP 握手 -> HTTP 请求 -> 解析 HTML -> 构建 DOM 树 -> 构建 CSSOM 树 -> 构建渲染树 -> 布局 -> 绘制)。
- 重排 (Reflow/Layout) 与 重绘 (Repaint):是什么,区别,如何减少。
- 网络协议:
- HTTP/HTTPS:状态码 (200, 301, 304, 403, 404, 500 等),请求方法 (GET/POST 区别),Headers (Cache-Control, ETag, Cookie, Content-Type 等)。
- HTTP 缓存:强缓存和协商缓存的机制和区别。
- 跨域 (CORS):原因和解决方案(JSONP, CORS, Nginx 反向代理)。
- TCP/IP:三次握手、四次挥手。
- 浏览器存储:
Cookie/localStorage/sessionStorage/IndexedDB的区别和应用场景。 - 安全性:XSS (跨站脚本攻击), CSRF (跨站请求伪造) 的原理和防范。
第五部分:性能优化 (Performance Optimization)
衡量一个前端工程师能力的重要标准。
- 加载性能优化:
- 资源压缩与合并:JS/CSS/HTML 压缩,图片压缩(WebP 格式)。
- 代码分割 (Code Splitting) 和 按需加载 (Lazy Loading)。
- Tree Shaking:移除无用代码。
- 使用 CDN。
- 渲染性能优化:
- 减少重排和重绘。
- 使用
requestAnimationFrame处理动画。 - 长列表的虚拟滚动 (Virtual Scrolling)。
- 性能监控与分析工具:
- Chrome DevTools (Lighthouse, Performance, Network 面板)。
window.performanceAPI。
第六部分:算法、数据结构与设计模式
大厂尤其看重这部分。
- 数据结构:数组、链表、栈、队列、哈希表、树(特别是二叉树)。要能理解其概念并知道在 JS 中如何实现。
- 算法:
- 排序算法(冒泡、快排)。
- 查找算法(二分查找)。
- 树的遍历(深度优先 DFS, 广度优先 BFS),这在处理 DOM 树时很常见。
- LeetCode 上的简单和中等难度的题目,特别是字符串和数组相关的。
- 设计模式:单例模式、工厂模式、观察者模式(发布-订阅)、装饰器模式等在前端中的应用。
在浏览器中输入地址回车后会发生什么
第一阶段:浏览器处理
URL 解析
缓存检查
强制缓存和协商缓存
第二阶段:网络连接
- DNS 域名解析
域名转ip地址
4.建立 TCP 连接
- 建立 TLS 连接 (仅限 HTTPS)
第三阶段:服务器处理
发送 HTTP 请求
服务器处理请求并响应
第四阶段:浏览器渲染
解析资源,构建 DOM/CSSOM
构建渲染树
布局
绘制
合成
项目中的图片懒加载怎么实现
[] == ![] 为什么是 true****?
解析(这是隐式转换规则(特别是 == 和 +)与 显式转换方法的问题):
![]:首先计算!运算符。[]是一个对象,在布尔上下文中是true。所以![]就是false。- 表达式变为:
[] == false。 - 根据规则
boolean == 任何类型,将boolean转换为number。false转换为0。 - 表达式变为:
[] == 0。 - 根据规则
对象 == number,将对象[]通过ToPrimitive转换为原始值。提示是number。- 调用
[].valueOf(),返回[]本身(不是原始值)。 - 继续调用
[].toString(),返回''(空字符串)。
- 调用
- 表达式变为:
'' == 0。 - 根据规则
string == number,将string转换为number。''转换为0。 - 表达式变为:
0 == 0。 - 结果:
true。
闭包 (Closure)是什么
当一个函数能够记住并访问它所在的词法作用域时,就产生了闭包,即使函数是在其当前词法作用域之外执行的。
当你(函数)离开房间(词法作用域)去别的地方执行时,这个背包让你依然能访问到房间里的那些物品(变量)。
function makeCounter() {
let count = 0; // count 位于 makeCounter 的词法作用域内
// 这个内部函数就是一个闭包
return function() {
count++; // 它可以访问并修改外部作用域的 count 变量
return count;
};
}调用函数后,返回匿名函数,虽然理论要销毁 count 这个变量,因为匿名函数和原来词法作用域里的变量仍然有联系引用,通过垃圾回收机制不去回收联系的变量,这样变量就被封闭住了。
优点:
1.提供私有变量,实现数据封装和隐藏 2.让变量的状态得以持久化
应用场景:
防抖节流模块化
缺点:内存泄漏,因为不怎么回收
执行上下文 (Execution Context) 与调用栈 (Call Stack)
JavaScript 代码执行的底层机制:执行上下文 和 调用栈。 **执行上下文:**每当一段代码准备执行时,JS 引擎都会为它创建一个执行上下文。
执行上下文主要有三种:1.全局执行上下文 2.函数执行上下文 3.Eval函数执行上下文
创建阶段:
1.创建词法环境
- 它记录了当前作用域内的所有变量、函数声明以及对外部环境的引用(这就是作用域链的基础)。
- 对于
let和const声明的变量,它们会被创建但不会被初始化,处于“未初始化”状态。这就是为什么在声明前访问它们会报错(暂时性死区,TDZ)。 - 对于
function声明,它会被完整创建并初始化,这就是为什么函数声明可以在定义之前被调用(函数提升)。
tips:
let 和 const 定义的函数(即函数表达式)不会被“完整地”提升,但它们声明的变量会被提升进入“暂时性死区”。
不可以在声明之前调用!
2.确定 this 的指向
执行阶段 在准备工作完成后,代码开始一行一行地执行。
深拷贝浅拷贝
核心:其实就是能不能完全把对象嵌套的属性也给复制过去的问题。
浅拷贝(只能拷贝一层 更深的还是引用的地址 不是完全拷贝):
1.Object.assign()
let originalObj = {
name: '张三',
age: 25,
hobbies: ['读书', '游泳']
};
// 使用 Object.assign 进行浅拷贝
let shallowCopy = Object.assign({}, originalObj);
// 修改原始类型的值
shallowCopy.name = '李四';
console.log(originalObj.name); // '张三' (不受影响)
// 修改引用类型的值
shallowCopy.hobbies.push('跑步');
console.log(originalObj.hobbies); // ['读书', '游泳', '跑步'] (被影响了!)2.扩展运算符 ...
3.Array.prototype.slice() 或 Array.from()
深拷贝(完全拷贝,更深的嵌套属性此刻也不是原引用了独立起来了):
1.JSON.parse(JSON.stringify(obj)) (简单但有缺陷)
2.递归函数 (最根本的解决方案)
3.现代浏览器内置方法 structuredClone() (推荐)
其实还得最后看polyfill一下 这个有点太新了貌似
4.使用第三方库 (如 Lodash)
cloneDeep
// 需要先安装 lodash: npm install lodash
import { cloneDeep } from 'lodash';
let originalObj = { /* ... */ };
let deepCopy = cloneDeep(originalObj);总结与对比
| 方法 | 类型 | 能否处理嵌套对象 | 优点 | 缺点 |
|---|---|---|---|---|
Object.assign() | 浅拷贝 | 否 | 简单 | 嵌套对象会共享引用 |
扩展运算符 ... | 浅拷贝 | 否 | 语法简洁,ES6 标准 | 嵌套对象会共享引用 |
JSON.parse/stringify | 深拷贝 | 能 | 简单快捷 | 类型丢失多,无法处理函数、循环引用 |
| 递归函数 | 深拷贝 | 能 | 可自定义,理解原理 | 实现复杂,需考虑各种边界情况 |
structuredClone() | 深拷贝 | 能 | 原生API,强大,性能好 | 无法拷贝函数、原型链 |
Lodash cloneDeep | 深拷贝 | 能 | 最健壮,功能最全 | 增加项目体积 |