十二月 21, 2025
41 分钟阅读

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

interview
career-advice
job-search
entry-level
初级后端开发工程师(Node.js)面试题:完整指南
MB

Milad Bonakdar

作者

掌握 Node.js 后端开发,包含 35 个必备面试题,涵盖 JavaScript 基础、异步编程、Express.js、数据库、API、安全等方面。为初级后端开发工程师面试做好充分准备。


引言

本综合指南包含 35 个精心挑选的面试问题,涵盖 Node.js 后端开发的基础知识。这些是初级后端开发人员在面试中实际遇到的问题。每个问题都包括详尽的答案、稀有度评估和难度评级,这些都基于对来自主要科技公司和初创公司的数百次真实面试的分析。

无论您是为您的第一个后端角色做准备,还是从前端开发转型而来,本指南都涵盖了从 JavaScript 基础知识到 API 设计、数据库管理、安全最佳实践和部署策略的所有内容。


JavaScript 基础 (8 个问题)

1. 解释 JavaScript 中 varletconst 的区别

答案:

  • var: 函数作用域,会被提升并初始化为 undefined,可以在同一作用域中重新声明,在现代代码中已基本弃用
  • let: 块作用域,会被提升但在声明之前处于暂时性死区(TDZ),不能在同一作用域中重新声明,可以重新赋值
  • const: 块作用域,会被提升但在 TDZ 中,必须在声明时初始化,不能重新赋值(但可以改变对象/数组的内容)

示例:

// var - 函数作用域
function example() {
  if (true) {
    var x = 1;
  }
  console.log(x); // 1(可以在块外部访问)
}

// let - 块作用域
if (true) {
  let y = 2;
}
console.log(y); // ReferenceError

// const - 不能重新赋值
const z = 3;
z = 4; // TypeError

const obj = { name: 'John' };
obj.name = 'Jane'; // OK - 修改属性
obj = {}; // TypeError - 不能重新赋值

最佳实践: 默认使用 const,需要重新赋值时使用 let,在现代 JavaScript 中永远不要使用 var

稀有度: 常见 难度: 简单


2. 什么是闭包?请提供一个 Node.js 中的实际示例

答案: 闭包是指内部函数可以访问其外部(封闭)函数作用域中的变量,即使在外部函数返回后也是如此。内部函数“闭合”了这些变量。

Node.js 实际示例:

// 中间件工厂模式
function createAuthMiddleware(secretKey) {
  // secretKey 被返回的函数 "闭合"
  return function(req, res, next) {
    const token = req.headers.authorization;
    if (validateToken(token, secretKey)) {
      next();
    } else {
      res.status(401).json({ error: 'Unauthorized' });
    }
  };
}

// 用法
const authMiddleware = createAuthMiddleware(process.env.JWT_SECRET);
app.use('/api/protected', authMiddleware);

优点:

  • 数据隐私(无法直接访问 secretKey)
  • 函数工厂
  • 模块模式实现
  • 在异步操作中维护状态

稀有度: 常见 难度: 中等


3. 解释 this 关键字,以及它在箭头函数中的不同之处

答案: this 指的是执行上下文。它的值取决于函数被调用的方式。

普通函数:

const obj = {
  name: "Server",
  greet: function() {
    console.log(this.name); // "Server"
  }
};
obj.greet(); // this = obj

const greet = obj.greet;
greet(); // this = undefined (严格模式) 或 global

箭头函数:

const obj = {
  name: "Server",
  greet: () => {
    console.log(this.name); // undefined (词法作用域)
  }
};
obj.greet(); // this = 词法作用域 (Node.js 中的模块作用域)

关键区别: 箭头函数没有自己的 this - 它们从封闭作用域继承它。

稀有度: 常见 难度: 中等


4. 什么是 Promise?它们与回调函数有什么不同?

答案: Promise 代表异步操作最终的完成(或失败)。

回调模式(回调地狱):

getUser(userId, (err, user) => {
  if (err) return handleError(err);
  getPosts(user.id, (err, posts) => {
    if (err) return handleError(err);
    getComments(posts[0].id, (err, comments) => {
      if (err) return handleError(err);
      // 嵌套回调 - 难以阅读
    });
  });
});

Promise 模式:

getUser(userId)
  .then(user => getPosts(user.id))
  .then(posts => getComments(posts[0].id))
  .then(comments => console.log(comments))
  .catch(err => handleError(err));

优点:

  • 避免回调地狱
  • 使用 .catch() 更好地进行错误处理
  • 可链式操作
  • 可以使用 Promise.all() 进行并行操作

稀有度: 常见 难度: 简单-中等


5. 什么是 async/await?它如何提高代码可读性?

答案: async/await 是构建在 Promise 之上的语法糖,使异步代码看起来和行为更像同步代码。

示例:

// 使用 Promise
function fetchUserData(userId) {
  return fetchUser(userId)
    .then(user => {
      return fetchPosts(user.id)
        .then(posts => {
          return { user, posts };
        });
    })
    .catch(error => console.error(error));
}

// 使用 async/await (更简洁)
async function fetchUserData(userId) {
  try {
    const user = await fetchUser(userId);
    const posts = await fetchPosts(user.id);
    return { user, posts };
  } catch (error) {
    console.error(error);
  }
}

要点:

  • async 函数总是返回一个 Promise
  • await 暂停执行,直到 Promise resolve
  • 使用 try/catch 进行错误处理
  • 使顺序操作更清晰

稀有度: 常见 难度: 中等


6. 解释对象和数组的解构

答案: 解构从数组中提取值或从对象中提取属性到不同的变量中。

数组解构:

const [first, second, ...rest] = [1, 2, 3, 4, 5];
// first = 1, second = 2, rest = [3, 4, 5]

// 跳过元素
const [primary, , tertiary] = ['red', 'green', 'blue'];
// primary = 'red', tertiary = 'blue'

对象解构:

const user = { name: 'Alice', age: 25, email: '[email protected]' };

const { name, age, city = 'NYC' } = user;
// name = 'Alice', age = 25, city = 'NYC' (默认值)

// 重命名变量
const { name: userName, age: userAge } = user;

// 嵌套解构
const { address: { street, zip } } = person;

函数参数:

function createUser({ name, email, role = 'user' }) {
  // 使用解构的参数
}

稀有度: 常见 难度: 简单-中等


7. 什么是展开运算符和剩余参数?

答案:

展开运算符 (...) - 展开可迭代对象:

// 数组
const arr1 = [1, 2, 3];
const arr2 = [...arr1, 4, 5]; // [1, 2, 3, 4, 5]

// 对象 (浅拷贝)
const user = { name: 'Alice', age: 25 };
const updatedUser = { ...user, age: 26 }; // 不可变更新

// 函数参数
const numbers = [1, 2, 3];
Math.max(...numbers); // 3

剩余参数 (...) - 收集多个元素:

// 函数参数
function sum(...numbers) {
  return numbers.reduce((a, b) => a + b, 0);
}
sum(1, 2, 3, 4); // 10

// 数组解构
const [first, ...remaining] = [1, 2, 3, 4];
// first = 1, remaining = [2, 3, 4]

关键区别: 展开是展开,剩余是收集。

稀有度: 常见 难度: 简单-中等


8. 解释常见的数组方法:map、filter、reduce、forEach

答案:

map - 转换每个元素,返回新数组:

const doubled = [1, 2, 3].map(x => x * 2); // [2, 4, 6]

filter - 保留符合条件的元素:

const evens = [1, 2, 3, 4].filter(x => x % 2 === 0); // [2, 4]

reduce - 归约为单个值:

const sum = [1, 2, 3].reduce((acc, val) => acc + val, 0); // 6
const grouped = users.reduce((acc, user) => {
  acc[user.role] = acc[user.role] || [];
  acc[user.role].push(user);
  return acc;
}, {});

forEach - 迭代,不返回新数组:

[1, 2, 3].forEach(item => console.log(item));

稀有度: 常见 难度: 简单


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 操作。

工作原理:

  1. 调用堆栈: 执行同步代码(LIFO)
  2. Node APIs: 处理异步操作 (fs, http, timers)
  3. 回调队列 (宏任务): 保存来自 Node APIs 的回调
  4. 微任务队列: 保存 Promise 回调(优先级更高)
  5. 事件循环: 当堆栈为空时,将任务从队列移动到调用堆栈

执行顺序:

console.log('1');

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

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

console.log('4');

// 输出:1, 4, 3, 2
// 解释:
// - 同步代码 (1, 4) 首先运行
// - 微任务 (Promise) 在宏任务之前运行
// - 宏任务 (setTimeout) 最后运行

事件循环的阶段:

  1. 定时器 (setTimeout, setInterval)
  2. 待定回调
  3. 空闲,准备
  4. Poll (获取新的 I/O 事件)
  5. Check (setImmediate 回调)
  6. 关闭回调

稀有度: 常见 难度: 困难


11. 阻塞代码和非阻塞代码有什么区别?

答案:

阻塞代码 - 暂停执行,直到操作完成:

// 同步文件读取 (阻塞)
const fs = require('fs');
const data = fs.readFileSync('file.txt', 'utf8');
console.log(data); // 等待文件读取
console.log('Done'); // 在文件读取后执行

非阻塞代码 - 继续执行,通过回调处理结果:

// 异步文件读取 (非阻塞)
const fs = require('fs');
fs.readFile('file.txt', 'utf8', (err, data) => {
  if (err) throw err;
  console.log(data);
});
console.log('Done'); // 立即执行,在文件读取完成之前

为什么非阻塞很重要:

  • 服务器可以并发处理多个请求
  • 更好的资源利用率
  • 改进 I/O 操作的性能
  • 可扩展性

稀有度: 常见 难度: 简单-中等


12. 什么是 Node.js 模块?模块系统如何工作?

答案: Node.js 使用 CommonJS 模块系统(但也支持 ES 模块)。

CommonJS (require/module.exports):

// math.js
function add(a, b) {
  return a + b;
}

module.exports = { add };
// 或
exports.add = add;

// app.js
const { add } = require('./math');
const result = add(2, 3);

ES Modules (import/export):

// math.js
export function add(a, b) {
  return a + b;
}

// app.js
import { add } from './math.js';

模块类型:

  • 核心模块: 内置 (fs, http, path)
  • 本地模块: 您自己的文件
  • 第三方模块: 通过 npm 安装

模块缓存: 模块在第一次 require 后会被缓存,因此后续的 require 返回相同的实例。

稀有度: 常见 难度: 简单


13. 解释 process.nextTick()setImmediate() 的区别

答案:

process.nextTick() - 在当前阶段执行回调,在任何其他异步操作之前:

console.log('1');

process.nextTick(() => {
  console.log('2');
});

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

console.log('4');

// 输出:1, 4, 2, 3
// nextTick 具有最高优先级,甚至高于 Promise

setImmediate() - 在事件循环的下一次迭代中执行回调:

console.log('1');

setImmediate(() => {
  console.log('2');
});

setTimeout(() => {
  console.log('3');
}, 0);

console.log('4');

// 输出:1, 4, 3, 2 (或 1, 4, 2, 3 取决于上下文)

优先级顺序:

  1. 同步代码
  2. process.nextTick() 回调
  3. Promise 回调 (微任务)
  4. setTimeout(0) / setImmediate() (宏任务)

用例:

  • nextTick:确保回调在其他异步操作之前运行
  • setImmediate:将执行推迟到下一个事件循环迭代

稀有度: 不常见 难度: 中等-困难


14. 什么是 Node.js 中的全局对象?

答案: Node.js 中的全局对象类似于浏览器中的 window 对象,但它被称为 global

全局属性:

// 无需 require 即可在任何地方使用
console.log(__dirname); // 当前目录路径
console.log(__filename); // 当前文件路径
console.log(process); // Process 对象
console.log(global); // 全局对象本身

常见的全局变量:

  • process - 进程信息和控制
  • Buffer - 处理二进制数据
  • setTimeout, setInterval, clearTimeout, clearInterval
  • setImmediate, clearImmediate
  • console - 控制台输出

注意: 在 ES 模块中,默认情况下 __dirname__filename 不可用。请改用 import.meta.url

稀有度: 常见 难度: 简单


15. 如何在 Node.js 应用程序中处理错误?

答案: Node.js 中的错误处理可以通过多种方法进行管理:

1. Try-catch 用于同步代码:

try {
  const data = fs.readFileSync('file.txt', 'utf8');
} catch (error) {
  console.error('Error reading file:', error.message);
}

2. 回调错误模式:

fs.readFile('file.txt', 'utf8', (err, data) => {
  if (err) {
    return console.error('Error:', err);
  }
  console.log(data);
});

3. Promise 错误处理:

fetchData()
  .then(data => processData(data))
  .catch(error => console.error('Error:', error));

4. Async/await 与 try-catch:

async function handleRequest() {
  try {
    const data = await fetchData();
    return data;
  } catch (error) {
    console.error('Error:', error);
    throw error; // 如果需要,重新抛出
  }
}

5. 全局错误处理程序:

// 未捕获的异常
process.on('uncaughtException', (error) => {
  console.error('Uncaught Exception:', error);
  process.exit(1);
});

// 未处理的 Promise 拒绝
process.on('unhandledRejection', (reason, promise) => {
  console.error('Unhandled Rejection:', reason);
});

6. Express 错误中间件:

app.use((err, req, res, next) => {
  console.error(err.stack);
  res.status(500).json({ error: 'Something went wrong!' });
});

稀有度: 常见 难度: 中等


Express.js & Web 框架 (6 个问题)

16. 什么是 Express.js?它的主要功能是什么?

答案: Express.js 是一个最小且灵活的 Node.js Web 应用程序框架,它提供了一组强大的功能来构建 Web 和移动应用程序。

主要功能:

  • 路由: 定义端点和 HTTP 方法
  • 中间件: 在请求-响应周期中执行的函数
  • 模板引擎: 渲染动态 HTML (EJS, Pug, Handlebars)
  • 错误处理: 集中式错误处理中间件
  • 静态文件: 提供静态资源
  • JSON 解析: 内置的 JSON 和 URL 编码数据的主体解析

基本示例:

const express = require('express');
const app = express();

app.use(express.json());

app.get('/', (req, res) => {
  res.json({ message: 'Hello World' });
});

app.listen(3000, () => {
  console.log('Server running on port 3000');
});

为什么选择 Express:

  • 最小且无偏见
  • 庞大的生态系统
  • 易于学习
  • 灵活的中间件系统

稀有度: 常见 难度: 简单


17. 什么是 Express.js 中的中间件?提供示例。

答案: 中间件函数是可以访问请求对象 (req)、响应对象 (res) 和应用程序的请求-响应周期中的 next 函数的函数。

中间件类型:

1. 应用程序级中间件:

app.use((req, res, next) => {
  console.log('Request received:', req.method, req.path);
  next(); // 将控制权传递给下一个中间件
});

2. 路由级中间件:

app.get('/users', authenticateUser, (req, res) => {
  res.json({ users: [] });
});

3. 错误处理中间件:

app.use((err, req, res, next) => {
  console.error(err.stack);
  res.status(500).json({ error: err.message });
});

4. 内置中间件:

app.use(express.json()); // 解析 JSON 主体
app.use(express.urlencoded({ extended: true })); // 解析 URL 编码
app.use(express.static('public')); // 提供静态文件

5. 第三方中间件:

const cors = require('cors');
const helmet = require('helmet');

app.use(cors());
app.use(helmet());

自定义身份验证中间件示例:

function authenticateUser(req, res, next) {
  const token = req.headers.authorization;
  if (!token) {
    return res.status(401).json({ error: 'No token provided' });
  }
  // 验证 token
  req.user = decodedToken;
  next();
}

稀有度: 常见 难度: 中等


18. 解释 Express 路由以及如何组织路由

答案: 路由是指应用程序的端点(URI)如何响应客户端请求。

基本路由:

app.get('/users', (req, res) => {
  res.json({ users: [] });
});

app.post('/users', (req, res) => {
  const newUser = req.body;
  res.status(201).json(newUser);
});

app.get('/users/:id', (req, res) => {
  const userId = req.params.id;
  res.json({ user: { id: userId } });
});

app.put('/users/:id', (req, res) => {
  // 更新用户
});

app.delete('/users/:id', (req, res) => {
  // 删除用户
});

路由参数:

app.get('/users/:userId/posts/:postId', (req, res) => {
  const { userId, postId } = req.params;
  // 访问路由参数
});

查询参数:

app.get('/search', (req, res) => {
  const { q, page, limit } = req.query;
  // ?q=nodejs&page=1&limit=10
});

使用 Express Router 组织路由:

// routes/users.js
const express = require('express');
const router = express.Router();

router.get('/', (req, res) => {
  res.json({ users: [] });
});

router.get('/:id', (req, res) => {
  res.json({ user: { id: req.params.id } });
});

module.exports = router;

// app.js
const userRoutes = require('./routes/users');
app.use('/api/users', userRoutes);

稀有度: 常见 难度: 简单-中等


19. 如何在 Express 中处理文件上传?

答案: 可以使用像 multer 这样的中间件来处理文件上传。

基本文件上传:

const multer = require('multer');
const upload = multer({ dest: 'uploads/' });

app.post('/upload', upload.single('file'), (req, res) => {
  // req.file 包含文件信息
  res.json({ 
    filename: req.file.filename,
    originalname: req.file.originalname,
    size: req.file.size
  });
});

多个文件:

app.post('/upload-multiple', upload.array('files', 10), (req, res) => {
  // req.files 是文件数组
  res.json({ uploaded: req.files.length });
});

自定义存储配置:

const storage = multer.diskStorage({
  destination: (req, file, cb) => {
    cb(null, 'uploads/');
  },
  filename: (req, file, cb) => {
    const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9);
    cb(null, file.fieldname + '-' + uniqueSuffix);
  }
});

const upload = multer({ 
  storage: storage,
  limits: { fileSize: 5 * 1024 * 1024 }, // 5MB 限制
  fileFilter: (req, file, cb) => {
    if (file.mimetype === 'image/jpeg' || file.mimetype === 'image/png') {
      cb(null, true);
    } else {
      cb(new Error('Only JPEG and PNG allowed'));
    }
  }
});

稀有度: 常见 难度: 中等


20. 什么是 CORS?如何在 Express 中处理它?

答案: CORS(跨域资源共享)是一种安全功能,它允许或限制 Web 页面向与提供 Web 页面的域不同的域发出请求。

问题: 浏览器默认阻止从 http://localhost:3000http://localhost:4000 的请求(不同的源)。

使用 cors 中间件的解决方案:

const cors = require('cors');

// 允许所有源(仅用于开发)
app.use(cors());

// 配置特定的源
app.use(cors({
  origin: 'https://example.com',
  methods: ['GET', 'POST', 'PUT', 'DELETE'],
  allowedHeaders: ['Content-Type', 'Authorization']
}));

// 多个源
app.use(cors({
  origin: ['https://example.com', 'https://app.example.com']
}));

手动 CORS 标头:

app.use((req, res, next) => {
  res.header('Access-Control-Allow-Origin', 'https://example.com');
  res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
  res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
  
  if (req.method === 'OPTIONS') {
    return res.sendStatus(200);
  }
  next();
});

稀有度: 常见 难度: 简单-中等


21. 如何组织大型 Express.js 应用程序?

答案: 将代码组织成逻辑模块和文件夹以提高可维护性。

推荐结构:

project/
├── src/
│   ├── controllers/
│   │   └── userController.js
│   ├── models/
│   │   └── User.js
│   ├── routes/
│   │   └── userRoutes.js
│   ├── middleware/
│   │   └── auth.js
│   ├── services/
│   │   └── userService.js
│   ├── utils/
│   │   └── helpers.js
│   ├── config/
│   │   └── database.js
│   └── app.js
├── tests/
├── .env
└── package.json

关注点分离示例:

Controller (处理 HTTP):

// controllers/userController.js
const userService = require('../services/userService');

exports.getUsers = async (req, res, next) => {
  try {
    const users = await userService.getAllUsers();
    res.json(users);
  } catch (error) {
    next(error);
  }
};

Service (业务逻辑):

// services/userService.js
const User = require('../models/User');

exports.getAllUsers = async () => {
  return await User.find();
};

Routes:

// routes/userRoutes.js
const express = require('express');
const router = express.Router();
const userController = require('../controllers/userController');

router.get('/', userController.getUsers);
router.post('/', userController.createUser);

module.exports = router;

App 设置:

// app.js
const express = require('express');
const userRoutes = require('./routes/userRoutes');

const app = express();
app.use(express.json());
app.use('/api/users', userRoutes);

稀有度: 常见 难度: 中等


数据库概念 (5 个问题)

22. SQL 和 NoSQL 数据库有什么区别?

答案:

SQL(关系型)数据库:

  • 使用表、行、列的结构化数据
  • 必须在使用前定义模式
  • 符合 ACID 标准(原子性、一致性、隔离性、持久性)
  • 示例:PostgreSQL、MySQL、SQLite
  • 最适合:复杂的查询、事务、结构化数据

NoSQL 数据库:

  • 灵活的模式或无模式
  • 各种数据模型(文档、键值、图形、列)
  • 水平扩展
  • 示例:MongoDB、Redis、Cassandra
  • 最适合:大规模应用程序、灵活的模式、快速开发

比较:

特性SQLNoSQL
模式固定灵活
可扩展性垂直水平
ACID不同
查询语言SQL不同
关系连接嵌入/引用

何时使用 SQL:

  • 复杂的查询和关系
  • 需要 ACID 合规性
  • 结构化数据
  • 金融交易

何时使用 NoSQL:

  • 快速开发
  • 大规模数据
  • 灵活的模式需求
  • 简单查询

稀有度: 常见 难度: 简单-中等


23. 如何在 Node.js 中连接到数据库?(MongoDB 示例)

答案: 以使用 Mongoose 的 MongoDB 为例:

基本连接:

const mongoose = require('mongoose');

// 连接字符串
const mongoURI = 'mongodb://localhost:27017/mydb';

// 连接
mongoose.connect(mongoURI, {
  useNewUrlParser: true,
  useUnifiedTopology: true
})
.then(() => console.log('MongoDB connected'))
.catch(err => console.error('Connection error:', err));

使用环境变量:

require('dotenv').config();

mongoose.connect(process.env.MONGODB_URI, {
  useNewUrlParser: true,
  useUnifiedTopology: true
});

连接事件:

mongoose.connection.on('connected', () => {
  console.log('Mongoose connected to MongoDB');
});

mongoose.connection.on('error', (err) => {
  console.error('Mongoose connection error:', err);
});

mongoose.connection.on('disconnected', () => {
  console.log('Mongoose disconnected');
});

定义模型:

const userSchema = new mongoose.Schema({
  name: { type: String, required: true },
  email: { type: String, required: true, unique: true },
  age: { type: Number, min: 0 }
}, { timestamps: true });

const User = mongoose.model('User', userSchema);

使用模型:

// 创建
const user = await User.create({ name: 'John', email: '[email protected]' });

// 读取
const users = await User.find();
const user = await User.findById(userId);

// 更新
await User.findByIdAndUpdate(userId, { name: 'Jane' });

// 删除
await User.findByIdAndDelete(userId);

稀有度: 常见 难度: 中等


24. 什么是 ORM/ODM?为什么要使用它?

答案: ORM(对象关系映射)/ ODM(对象文档映射)是一种技术,它允许您使用面向对象的范例与数据库交互,而不是编写原始 SQL 查询。

优点:

  • 抽象: 使用 JavaScript 对象而不是 SQL
  • 类型安全: 模式验证
  • 关系: 轻松处理关系
  • 安全性: 防止 SQL 注入
  • 迁移: 数据库模式的版本控制
  • 开发人员体验: 更直观的 API

示例比较:

原始 SQL:

const query = 'SELECT * FROM users WHERE email = ?';
db.query(query, [email], (err, results) => {
  // 处理结果
});

使用 ORM(Sequelize 用于 SQL):

const user = await User.findOne({ where: { email: email } });

使用 ODM(Mongoose 用于 MongoDB):

const user = await User.findOne({ email: email });

流行的 ORM/ODM:

  • Mongoose: MongoDB (ODM)
  • Sequelize: PostgreSQL、MySQL、SQLite (ORM)
  • TypeORM: TypeScript ORM
  • Prisma: 具有类型安全性的现代 ORM

稀有度: 常见 难度: 简单-中等


25. 解释数据库索引以及为什么它很重要

答案: 数据库索引是一种数据结构,可以提高数据库表中数据检索操作的速度。

工作原理:

  • 创建单独的数据结构(如 B 树)
  • 存储指向实际数据的指针
Newsletter subscription

真正有效的每周职业建议

将最新见解直接发送到您的收件箱

Decorative doodle

创建一份让您被录用速度提高60%的简历

在几分钟内,创建一份量身定制的、ATS友好的简历,已证明可以获得6倍以上的面试机会。

创建更好的简历

分享这篇文章

让您的6秒钟发挥作用

招聘人员平均只花6到7秒扫描简历。我们经过验证的模板旨在立即吸引注意力并让他们继续阅读。