面试题答案
一键面试一、模块导出方式
- CommonJS 导出:使用
module.exports
或exports
导出模块中的变量、函数或对象。例如:
// math.js
function add(a, b) {
return a + b;
}
module.exports = {
add: add
};
这种方式简单直观,在 Node.js 环境中广泛应用,能清晰定义模块对外暴露的接口。
- ES6 模块导出:通过
export
关键字导出常量、函数、类等。有命名导出和默认导出两种形式。
// utils.js
export const PI = 3.14159;
export function square(x) {
return x * x;
}
// 或默认导出
export default function greet(name) {
return `Hello, ${name}!`;
}
ES6 模块导出更加灵活,能提高代码的可读性和可维护性,特别是在大型项目中便于组织代码结构。
二、依赖管理
- 使用 npm 或 yarn:在项目根目录初始化
package.json
文件,通过npm install
或yarn add
安装项目依赖。将依赖包的版本信息记录在package.json
中,方便团队协作和部署。例如:
npm init -y
npm install express
-
依赖版本锁定:使用
npm shrinkwrap
或yarn.lock
文件锁定依赖包的精确版本,确保在不同环境下安装的依赖版本一致,避免因版本差异导致的兼容性问题。 -
按需加载依赖:在模块中只引入实际需要的依赖,避免引入不必要的模块,减少项目体积和加载时间。例如,在一个只需要处理 HTTP 请求部分功能的模块中,只引入相关的 HTTP 处理模块的特定方法,而不是整个模块。
三、模块设计原则
- 单一职责原则:每个模块应该只负责一项主要功能,这样模块功能明确,易于理解、维护和测试。例如,在一个电商项目中,将用户登录、商品展示、订单处理等功能分别放在不同的模块中。
- 高内聚低耦合:模块内部的元素应该紧密相关(高内聚),而模块之间的依赖关系应尽量简单、松散(低耦合)。例如,在一个博客系统中,文章发布模块与评论模块相对独立,通过简单的接口进行交互,互不干扰内部实现。
- 开闭原则:模块应该对扩展开放,对修改关闭。当需求变化时,优先通过扩展现有模块来实现新功能,而不是直接修改模块内部代码。例如,在一个日志记录模块中,可以通过增加新的日志处理器类来支持不同类型的日志输出(如文件日志、数据库日志),而不改变原有日志记录的核心逻辑。
四、常见的模块设计模式及其应用
- Singleton 模式:确保一个模块在整个应用程序中只有一个实例。适用于需要全局唯一状态或资源的场景,如数据库连接池模块。
// dbConnection.js
let instance;
function getDbConnection() {
if (!instance) {
// 实际创建数据库连接的逻辑
instance = require('mysql').createConnection({
host: 'localhost',
user: 'root',
password: 'password',
database: 'test'
});
}
return instance;
}
module.exports = getDbConnection;
- Factory 模式:用于创建对象,将对象的创建和使用分离。在一个图形绘制项目中,可以创建一个图形工厂模块,根据传入的参数创建不同类型的图形(如圆形、矩形)。
// shapeFactory.js
function createCircle(radius) {
return {
type: 'circle',
radius: radius,
draw: function() {
console.log(`Drawing a circle with radius ${this.radius}`);
}
};
}
function createRectangle(width, height) {
return {
type:'rectangle',
width: width,
height: height,
draw: function() {
console.log(`Drawing a rectangle with width ${this.width} and height ${this.height}`);
}
};
}
module.exports = {
createCircle: createCircle,
createRectangle: createRectangle
};
- Observer 模式:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知并自动更新。在一个实时聊天系统中,消息发布模块可以作为被观察对象,而各个聊天窗口作为观察者,当有新消息发布时,所有聊天窗口都能及时收到通知并更新显示。
// eventEmitter.js
class EventEmitter {
constructor() {
this.listeners = {};
}
on(eventName, callback) {
if (!this.listeners[eventName]) {
this.listeners[eventName] = [];
}
this.listeners[eventName].push(callback);
}
emit(eventName, ...args) {
if (this.listeners[eventName]) {
this.listeners[eventName].forEach(callback => callback(...args));
}
}
}
module.exports = new EventEmitter();
在其他模块中可以这样使用:
// chatWindow.js
const eventEmitter = require('./eventEmitter');
eventEmitter.on('newMessage', (message) => {
console.log(`Received new message: ${message}`);
});
// messagePublisher.js
const eventEmitter = require('./eventEmitter');
function publishMessage(message) {
eventEmitter.emit('newMessage', message);
}
module.exports = {
publishMessage: publishMessage
};