JavaScript 面试题标准答案模板(对应前文核心考点)

以下模板按"考点分类+问题+标准答案"结构整理,覆盖中高级面试高频题,可直接背诵并结合实际场景调整,确保答题逻辑清晰、要点全面。

一、原型链与继承类面试题

  1. 问题:请解释 JS 中 prototype、proto、constructor 的关系

标准答案:

三者是构成 JS 原型链的核心,核心关系可总结为一句话:实例的 proto 指向其构造函数的 prototype,而原型对象的 constructor 指向关联的构造函数。

• prototype:仅函数独有,是构造函数的"原型对象",用于存储所有实例共享的属性和方法(如 Array.prototype.push),避免实例重复创建相同方法造成内存浪费;

proto:所有对象独有,是实例的"原型指针",本质是访问原型对象的内部属性(ES6 推荐用 Object.getPrototypeOf() 替代,避免直接操作),实例通过它关联到构造函数的 prototype;

• constructor:仅原型对象独有,默认指向创建该原型对象的构造函数(如 User.prototype.constructor === User),实例可通过原型链继承该属性,用于判断实例的构造函数类型。

  1. 问题:ES6 class 与 ES5 原型继承有什么区别?

标准答案:

ES6 class 是 ES5 原型继承的语法糖,底层仍基于原型链实现,但存在 3 个关键差异,让代码更符合传统 OOP 语法规范:

  1. 调用限制:class 不能像 ES5 构造函数一样直接调用(如 User() 会报错),必须用 new 关键字创建实例,避免误调用导致全局变量污染;

  2. 方法可枚举性:class 定义的方法默认不可枚举(无法通过 for...in 遍历),而 ES5 原型上的方法默认可枚举(需手动用 Object.defineProperty 设置不可枚举);

  3. 继承逻辑:class 继承需通过 extends 关键字声明,且子类构造函数必须调用 super()(本质是借调父类构造函数,等价于 ES5 的 Parent.call(this)),而 ES5 继承需手动修改子类原型指向(Child.prototype = Object.create(Parent.prototype))并修复 constructor 指向,步骤更繁琐。

二、事件循环(Event Loop)类面试题

  1. 问题:请描述 JS 事件循环的执行流程

标准答案:

JS 是单线程语言,事件循环是实现异步的核心机制,核心逻辑是"同步优先、微任务先于宏任务",具体流程分 4 步:

  1. 执行同步代码:所有同步代码按顺序进入调用栈(Call Stack)执行,遇到异步任务时,将宏任务(如 setTimeout)放入"宏任务队列",微任务(如 Promise.then)放入"微任务队列";

  2. 清空微任务队列:同步代码执行完毕后,立即遍历微任务队列,按顺序执行所有微任务(执行过程中产生的新微任务会追加到队列末尾,一并执行),直到微任务队列为空;

  3. 执行一个宏任务:微任务清空后,从宏任务队列头部取出一个宏任务执行(仅执行一个,而非全部);

  4. 循环重复:重复上述 1-3 步,形成"事件循环",直到所有任务执行完毕。

  5. 问题:setTimeout 为什么会出现延迟不准的情况?

标准答案:

setTimeout 的延迟时间(如 setTimeout(fn, 1000) 中的 1000ms)是"最小等待时间",而非"精确执行时间",延迟不准的核心原因有两点:

  1. 同步代码阻塞:若调用栈中存在耗时同步代码(如大型循环),setTimeout 会等待同步代码完全执行完毕后,才会将回调函数放入宏任务队列,导致实际等待时间超过设定延迟;

  2. 宏任务队列排队:setTimeout 属于宏任务,即使回调函数进入队列,也需等待队列中前面的宏任务(如 DOM 事件回调、其他 setTimeout)执行完毕后才能运行,进一步增加延迟。

例如:若同步代码执行耗时 2s,即使 setTimeout 设定 1s 延迟,回调也会在 2s 后才执行。

三、内存管理与泄漏类面试题

  1. 问题:JS 中常见的内存泄漏场景有哪些?如何解决?

标准答案:

内存泄漏是指"不再使用的对象仍被引用,无法被垃圾回收器(GC)释放",常见场景及解决方案如下:

  1. 意外全局变量:未用 let/const 声明的变量(如 a = 10)会自动成为全局变量,被 window 长期引用。解决:所有变量用 let/const 声明,减少不必要的全局变量,用模块封装代码;

  2. 闭包长期引用:闭包会保留外部变量引用,若闭包被全局变量持有(如 window.counter = 闭包函数),外部变量无法回收。解决:闭包使用完后主动解除引用(如 counter = null),避免将闭包赋值给全局变量;

  3. 未清理的 DOM 引用:DOM 元素被删除后,若仍有变量引用(如 let btn = document.getElementById("btn")),浏览器无法回收 DOM 内存。解决:删除 DOM 后将引用设为 null(btn = null),用 WeakMap 存储 DOM 引用(无引用时自动回收);

  4. 未清理的定时器/事件监听:setInterval、addEventListener 未清理,回调函数会一直被引用。解决:定时器用 clearInterval 清理,组件卸载时用 removeEventListener 移除监听。

  5. 问题:如何用 Chrome 开发者工具排查内存泄漏?

标准答案:

排查核心是"跟踪内存变化+定位泄漏对象",关键步骤如下:

  1. 打开工具:打开目标页面,按 F12 打开 Chrome 开发者工具,切换到 Memory 面板;

  2. 跟踪内存分配:选择 Allocation Instrumenter Timings 模式(可实时记录内存分配情况),点击 Start 开始记录;

  3. 模拟用户操作:重复触发可能导致泄漏的操作(如切换组件、点击按钮),观察内存曲线;

  4. 判断泄漏:若内存曲线持续上升且操作结束后不回落(无明显下降),说明存在内存泄漏;

  5. 定位泄漏对象:切换到 Heap snapshot 模式,点击 Take snapshot 拍摄内存快照,筛选"Detached DOM nodes"(脱离文档的 DOM 节点)或"Closures"(闭包),查看未被回收的大对象,结合代码定位引用源头(如全局变量、未清理的监听)。

四、工程化(模块化+Webpack)类面试题

  1. 问题:ES Module(ESM)与 CommonJS 有什么关键区别?

标准答案:

两者是 JS 主流模块化规范,核心区别体现在 3 个维度,也是 ESM 取代 CommonJS 的原因:

  1. 加载时机:ESM 是"编译时加载"(静态分析),在代码编译阶段就能确定依赖关系,支持 Tree-Shaking(剔除未使用代码);CommonJS 是"运行时加载"(动态加载),执行到 require 时才加载模块,无法做静态优化;

  2. 导出方式:ESM 导出的是"模块引用",模块内部值变化时,导入方会同步更新(如 export let a = 1,修改 a 后导入方的 a 也会变);CommonJS 导出的是"值的拷贝",导出后模块内部值变化不影响导入方;

  3. this 指向:ESM 模块中 this 是 undefined(避免全局污染);CommonJS 模块中 this 指向 module.exports(类似全局对象)。

  4. 问题:请简述 Webpack 的核心原理和打包流程

标准答案:

Webpack 是前端构建工具,核心是"将多个模块(JS/CSS/图片等)打包成浏览器可识别的 bundle 文件",核心原理基于"模块依赖解析+资源转换"。

核心概念:

• Entry:入口文件(如 src/index.js),Webpack 从这里开始递归解析所有依赖;

• Output:输出配置(如 dist/main.js),指定打包后文件的路径和名称;

• Loader:处理非 JS 模块的"转换器"(如 css-loader 解析 CSS,babel-loader 将 ES6 转 ES5);

• Plugin:扩展 Webpack 功能的"插件"(如 HtmlWebpackPlugin 生成 HTML 文件,TerserPlugin 压缩 JS)。

打包流程:

  1. 初始化:读取 Webpack 配置文件,确定 Entry、Output、Loader、Plugin 等配置;

  2. 解析依赖:从 Entry 出发,递归解析所有 import/require 依赖,生成模块依赖图谱;

  3. 资源转换:用对应 Loader 处理非 JS 模块(如 CSS 转成 JS 模块),将所有资源统一转为 JS 模块;

  4. 生成 AST 与优化:将 JS 模块转为抽象语法树(AST),分析依赖关系,执行 Tree-Shaking 剔除未使用代码;

  5. 生成 bundle:合并所有优化后的模块,生成最终的 bundle 文件(如 main.js),完成打包。

相关推荐
Cobyte14 分钟前
模板 DSL 解析器中的状态机设计
前端·javascript·vue.js
软件开发技术深度爱好者1 小时前
小学英语单词魔法学园HTML5实现
javascript·html5·英语学习
勉灬之2 小时前
Next.js + Prisma 跨平台部署踩坑记
开发语言·javascript·ecmascript
糖果店的幽灵2 小时前
langgraph分支之 - 动态分支(Dynamic Branch)
java·前端·javascript·人工智能·langgraph
我叫黑大帅2 小时前
我为什么单一消费者的场景下,要用 Redis List 当消息队列?
redis·后端·面试
吃饱了得干活2 小时前
亿级订单表分库分表设计,从0到1全流程
java·数据库·面试
这是个栗子2 小时前
前端开发中的常用工具函数(九)
开发语言·javascript·ecmascript·at
Revolution613 小时前
一段 JavaScript 代码执行时,到底发生了什么
前端·javascript
程序员爱钓鱼5 小时前
Go 开发环境安装(Windows、macOS、Linux)
后端·面试·go
触底反弹5 小时前
🤯 面试被问 AI Workflow 和 Agent 有啥区别?3 张图 + 2 段代码讲清楚!
人工智能·设计模式·面试