初级后端开发工程师(Node.js)面试题:完整指南

Milad Bonakdar
作者
掌握 Node.js 后端开发,包含 35 个必备面试题,涵盖 JavaScript 基础、异步编程、Express.js、数据库、API、安全等方面。为初级后端开发工程师面试做好充分准备。
引言
本综合指南包含 35 个精心挑选的面试问题,涵盖 Node.js 后端开发的基础知识。这些是初级后端开发人员在面试中实际遇到的问题。每个问题都包括详尽的答案、稀有度评估和难度评级,这些都基于对来自主要科技公司和初创公司的数百次真实面试的分析。
无论您是为您的第一个后端角色做准备,还是从前端开发转型而来,本指南都涵盖了从 JavaScript 基础知识到 API 设计、数据库管理、安全最佳实践和部署策略的所有内容。
JavaScript 基础 (8 个问题)
1. 解释 JavaScript 中 var、let 和 const 的区别
答案:
var: 函数作用域,会被提升并初始化为undefined,可以在同一作用域中重新声明,在现代代码中已基本弃用let: 块作用域,会被提升但在声明之前处于暂时性死区(TDZ),不能在同一作用域中重新声明,可以重新赋值const: 块作用域,会被提升但在 TDZ 中,必须在声明时初始化,不能重新赋值(但可以改变对象/数组的内容)
示例:
最佳实践: 默认使用 const,需要重新赋值时使用 let,在现代 JavaScript 中永远不要使用 var。
稀有度: 常见 难度: 简单
2. 什么是闭包?请提供一个 Node.js 中的实际示例
答案: 闭包是指内部函数可以访问其外部(封闭)函数作用域中的变量,即使在外部函数返回后也是如此。内部函数“闭合”了这些变量。
Node.js 实际示例:
优点:
- 数据隐私(无法直接访问 secretKey)
- 函数工厂
- 模块模式实现
- 在异步操作中维护状态
稀有度: 常见 难度: 中等
3. 解释 this 关键字,以及它在箭头函数中的不同之处
答案: this 指的是执行上下文。它的值取决于函数被调用的方式。
普通函数:
箭头函数:
关键区别: 箭头函数没有自己的 this - 它们从封闭作用域继承它。
稀有度: 常见 难度: 中等
4. 什么是 Promise?它们与回调函数有什么不同?
答案: Promise 代表异步操作最终的完成(或失败)。
回调模式(回调地狱):
Promise 模式:
优点:
- 避免回调地狱
- 使用
.catch()更好地进行错误处理 - 可链式操作
- 可以使用
Promise.all()进行并行操作
稀有度: 常见 难度: 简单-中等
5. 什么是 async/await?它如何提高代码可读性?
答案: async/await 是构建在 Promise 之上的语法糖,使异步代码看起来和行为更像同步代码。
示例:
要点:
async函数总是返回一个 Promiseawait暂停执行,直到 Promise resolve- 使用
try/catch进行错误处理 - 使顺序操作更清晰
稀有度: 常见 难度: 中等
6. 解释对象和数组的解构
答案: 解构从数组中提取值或从对象中提取属性到不同的变量中。
数组解构:
对象解构:
函数参数:
稀有度: 常见 难度: 简单-中等
7. 什么是展开运算符和剩余参数?
答案:
展开运算符 (...) - 展开可迭代对象:
剩余参数 (...) - 收集多个元素:
关键区别: 展开是展开,剩余是收集。
稀有度: 常见 难度: 简单-中等
8. 解释常见的数组方法:map、filter、reduce、forEach
答案:
map - 转换每个元素,返回新数组:
filter - 保留符合条件的元素:
reduce - 归约为单个值:
forEach - 迭代,不返回新数组:
稀有度: 常见 难度: 简单
Node.js 基础 (7 个问题)
9. 什么是 Node.js?它与传统的服务器端语言有什么不同?
答案: Node.js 是一个 JavaScript 运行时,构建在 Chrome 的 V8 JavaScript 引擎之上,允许 JavaScript 在服务器端运行。
主要区别:
- 单线程事件循环: 使用非阻塞 I/O 模型,而不是多线程阻塞 I/O
- 默认异步: 操作不会阻塞主线程
- JavaScript 无处不在: 前端和后端使用相同的语言
- NPM 生态系统: 世界上最大的软件包注册表
- 快速执行: V8 引擎将 JavaScript 编译为本机机器代码
何时使用 Node.js:
- 实时应用程序(聊天、游戏)
- API 服务器
- 微服务
- 数据流应用程序
- I/O 密集型应用程序
何时不使用:
- CPU 密集型任务(图像处理、视频编码)
- 需要复杂计算的应用程序
稀有度: 常见 难度: 简单-中等
10. 解释 Node.js 中的事件循环
答案: 事件循环是一种机制,允许 Node.js 在单线程的情况下执行非阻塞 I/O 操作。
工作原理:
- 调用堆栈: 执行同步代码(LIFO)
- Node APIs: 处理异步操作 (fs, http, timers)
- 回调队列 (宏任务): 保存来自 Node APIs 的回调
- 微任务队列: 保存 Promise 回调(优先级更高)
- 事件循环: 当堆栈为空时,将任务从队列移动到调用堆栈
执行顺序:
事件循环的阶段:
- 定时器 (setTimeout, setInterval)
- 待定回调
- 空闲,准备
- Poll (获取新的 I/O 事件)
- Check (setImmediate 回调)
- 关闭回调
稀有度: 常见 难度: 困难
11. 阻塞代码和非阻塞代码有什么区别?
答案:
阻塞代码 - 暂停执行,直到操作完成:
非阻塞代码 - 继续执行,通过回调处理结果:
为什么非阻塞很重要:
- 服务器可以并发处理多个请求
- 更好的资源利用率
- 改进 I/O 操作的性能
- 可扩展性
稀有度: 常见 难度: 简单-中等
12. 什么是 Node.js 模块?模块系统如何工作?
答案: Node.js 使用 CommonJS 模块系统(但也支持 ES 模块)。
CommonJS (require/module.exports):
ES Modules (import/export):
模块类型:
- 核心模块: 内置 (fs, http, path)
- 本地模块: 您自己的文件
- 第三方模块: 通过 npm 安装
模块缓存: 模块在第一次 require 后会被缓存,因此后续的 require 返回相同的实例。
稀有度: 常见 难度: 简单
13. 解释 process.nextTick() 和 setImmediate() 的区别
答案:
process.nextTick() - 在当前阶段执行回调,在任何其他异步操作之前:
setImmediate() - 在事件循环的下一次迭代中执行回调:
优先级顺序:
- 同步代码
process.nextTick()回调- Promise 回调 (微任务)
setTimeout(0)/setImmediate()(宏任务)
用例:
nextTick:确保回调在其他异步操作之前运行setImmediate:将执行推迟到下一个事件循环迭代
稀有度: 不常见 难度: 中等-困难
14. 什么是 Node.js 中的全局对象?
答案: Node.js 中的全局对象类似于浏览器中的 window 对象,但它被称为 global。
全局属性:
常见的全局变量:
process- 进程信息和控制Buffer- 处理二进制数据setTimeout,setInterval,clearTimeout,clearIntervalsetImmediate,clearImmediateconsole- 控制台输出
注意: 在 ES 模块中,默认情况下 __dirname 和 __filename 不可用。请改用 import.meta.url。
稀有度: 常见 难度: 简单
15. 如何在 Node.js 应用程序中处理错误?
答案: Node.js 中的错误处理可以通过多种方法进行管理:
1. Try-catch 用于同步代码:
2. 回调错误模式:
3. Promise 错误处理:
4. Async/await 与 try-catch:
5. 全局错误处理程序:
6. Express 错误中间件:
稀有度: 常见 难度: 中等
Express.js & Web 框架 (6 个问题)
16. 什么是 Express.js?它的主要功能是什么?
答案: Express.js 是一个最小且灵活的 Node.js Web 应用程序框架,它提供了一组强大的功能来构建 Web 和移动应用程序。
主要功能:
- 路由: 定义端点和 HTTP 方法
- 中间件: 在请求-响应周期中执行的函数
- 模板引擎: 渲染动态 HTML (EJS, Pug, Handlebars)
- 错误处理: 集中式错误处理中间件
- 静态文件: 提供静态资源
- JSON 解析: 内置的 JSON 和 URL 编码数据的主体解析
基本示例:
为什么选择 Express:
- 最小且无偏见
- 庞大的生态系统
- 易于学习
- 灵活的中间件系统
稀有度: 常见 难度: 简单
17. 什么是 Express.js 中的中间件?提供示例。
答案: 中间件函数是可以访问请求对象 (req)、响应对象 (res) 和应用程序的请求-响应周期中的 next 函数的函数。
中间件类型:
1. 应用程序级中间件:
2. 路由级中间件:
3. 错误处理中间件:
4. 内置中间件:
5. 第三方中间件:
自定义身份验证中间件示例:
稀有度: 常见 难度: 中等
18. 解释 Express 路由以及如何组织路由
答案: 路由是指应用程序的端点(URI)如何响应客户端请求。
基本路由:
路由参数:
查询参数:
使用 Express Router 组织路由:
稀有度: 常见 难度: 简单-中等
19. 如何在 Express 中处理文件上传?
答案: 可以使用像 multer 这样的中间件来处理文件上传。
基本文件上传:
多个文件:
自定义存储配置:
稀有度: 常见 难度: 中等
20. 什么是 CORS?如何在 Express 中处理它?
答案: CORS(跨域资源共享)是一种安全功能,它允许或限制 Web 页面向与提供 Web 页面的域不同的域发出请求。
问题: 浏览器默认阻止从 http://localhost:3000 到 http://localhost:4000 的请求(不同的源)。
使用 cors 中间件的解决方案:
手动 CORS 标头:
稀有度: 常见 难度: 简单-中等
21. 如何组织大型 Express.js 应用程序?
答案: 将代码组织成逻辑模块和文件夹以提高可维护性。
推荐结构:
关注点分离示例:
Controller (处理 HTTP):
Service (业务逻辑):
Routes:
App 设置:
稀有度: 常见 难度: 中等
数据库概念 (5 个问题)
22. SQL 和 NoSQL 数据库有什么区别?
答案:
SQL(关系型)数据库:
- 使用表、行、列的结构化数据
- 必须在使用前定义模式
- 符合 ACID 标准(原子性、一致性、隔离性、持久性)
- 示例:PostgreSQL、MySQL、SQLite
- 最适合:复杂的查询、事务、结构化数据
NoSQL 数据库:
- 灵活的模式或无模式
- 各种数据模型(文档、键值、图形、列)
- 水平扩展
- 示例:MongoDB、Redis、Cassandra
- 最适合:大规模应用程序、灵活的模式、快速开发
比较:
何时使用 SQL:
- 复杂的查询和关系
- 需要 ACID 合规性
- 结构化数据
- 金融交易
何时使用 NoSQL:
- 快速开发
- 大规模数据
- 灵活的模式需求
- 简单查询
稀有度: 常见 难度: 简单-中等
23. 如何在 Node.js 中连接到数据库?(MongoDB 示例)
答案: 以使用 Mongoose 的 MongoDB 为例:
基本连接:
使用环境变量:
连接事件:
定义模型:
使用模型:
稀有度: 常见 难度: 中等
24. 什么是 ORM/ODM?为什么要使用它?
答案: ORM(对象关系映射)/ ODM(对象文档映射)是一种技术,它允许您使用面向对象的范例与数据库交互,而不是编写原始 SQL 查询。
优点:
- 抽象: 使用 JavaScript 对象而不是 SQL
- 类型安全: 模式验证
- 关系: 轻松处理关系
- 安全性: 防止 SQL 注入
- 迁移: 数据库模式的版本控制
- 开发人员体验: 更直观的 API
示例比较:
原始 SQL:
使用 ORM(Sequelize 用于 SQL):
使用 ODM(Mongoose 用于 MongoDB):
流行的 ORM/ODM:
- Mongoose: MongoDB (ODM)
- Sequelize: PostgreSQL、MySQL、SQLite (ORM)
- TypeORM: TypeScript ORM
- Prisma: 具有类型安全性的现代 ORM
稀有度: 常见 难度: 简单-中等
25. 解释数据库索引以及为什么它很重要
答案: 数据库索引是一种数据结构,可以提高数据库表中数据检索操作的速度。
工作原理:
- 创建单独的数据结构(如 B 树)
- 存储指向实际数据的指针



