Search K
Appearance
Appearance
📊 SEO元描述:2024年最新JavaScript模块模式教程,详解模块化设计、命名空间、揭示模块模式、单例模式。包含完整代码示例和最佳实践,适合初学者快速掌握JavaScript模块化编程。
核心关键词:JavaScript模块模式2024、模块化设计、命名空间模式、揭示模块模式、JavaScript封装
长尾关键词:JavaScript模块模式怎么实现、模块化设计原则、JavaScript命名空间、揭示模块模式优缺点、模块模式最佳实践
通过本节JavaScript模块模式详解,你将系统性掌握:
模块模式是什么?模块模式是JavaScript中实现封装和模块化的设计模式,通过闭包和IIFE创建私有作用域,提供公共接口,也是大型JavaScript应用的基础架构模式。
💡 学习建议:模块模式是JavaScript架构设计的基础,要重点理解封装原理和接口设计
经典模块模式使用IIFE创建私有作用域,通过返回对象暴露公共接口。
// 🎉 基本模块模式结构
var BasicModule = (function() {
// 私有变量
var privateVariable = "私有数据";
var privateCounter = 0;
// 私有方法
function privateMethod() {
console.log("这是私有方法");
return privateVariable;
}
function incrementCounter() {
privateCounter++;
}
// 公共接口
return {
// 公共方法
publicMethod: function() {
console.log("调用公共方法");
return privateMethod();
},
getCounter: function() {
return privateCounter;
},
increment: function() {
incrementCounter();
console.log("计数器增加到:", privateCounter);
},
// 公共属性
version: "1.0.0"
};
})();
// 使用模块
console.log("=== 基本模块模式示例 ===");
console.log(BasicModule.publicMethod()); // 私有数据
BasicModule.increment(); // 计数器增加到:1
console.log("当前计数:", BasicModule.getCounter()); // 1
console.log("模块版本:", BasicModule.version); // 1.0.0
// 无法访问私有成员
console.log("私有变量:", BasicModule.privateVariable); // undefined
// 🎉 可配置的模块模式
var ConfigurableModule = (function(config) {
// 使用配置初始化私有变量
var settings = {
debug: config.debug || false,
apiUrl: config.apiUrl || "https://api.example.com",
timeout: config.timeout || 5000,
retries: config.retries || 3
};
var requestCount = 0;
var errorLog = [];
// 私有方法
function log(message, level) {
if (settings.debug) {
console.log(`[${level.toUpperCase()}] ${message}`);
}
}
function makeRequest(endpoint, options) {
requestCount++;
log(`Making request to ${endpoint}`, 'info');
// 模拟请求
return new Promise((resolve, reject) => {
setTimeout(() => {
if (Math.random() > 0.8) {
var error = `Request failed: ${endpoint}`;
errorLog.push({
error: error,
timestamp: new Date(),
endpoint: endpoint
});
log(error, 'error');
reject(new Error(error));
} else {
log(`Request successful: ${endpoint}`, 'info');
resolve({ data: "模拟数据", status: 200 });
}
}, 100);
});
}
// 公共接口
return {
get: function(endpoint) {
return makeRequest(endpoint, { method: 'GET' });
},
post: function(endpoint, data) {
return makeRequest(endpoint, { method: 'POST', data: data });
},
getStats: function() {
return {
requestCount: requestCount,
errorCount: errorLog.length,
successRate: ((requestCount - errorLog.length) / requestCount * 100).toFixed(2) + '%'
};
},
getErrors: function() {
return errorLog.slice(); // 返回副本
},
updateConfig: function(newConfig) {
Object.assign(settings, newConfig);
log('Configuration updated', 'info');
},
getConfig: function() {
return Object.assign({}, settings); // 返回副本
}
};
})({
debug: true,
apiUrl: "https://my-api.com",
timeout: 8000
});
console.log("=== 可配置模块示例 ===");
ConfigurableModule.get("/users").then(result => {
console.log("请求结果:", result);
console.log("统计信息:", ConfigurableModule.getStats());
}).catch(error => {
console.log("请求错误:", error.message);
console.log("错误日志:", ConfigurableModule.getErrors());
});
// 🎉 模块间依赖
var UtilsModule = (function() {
return {
formatDate: function(date) {
return date.toLocaleDateString('zh-CN');
},
formatCurrency: function(amount, currency) {
return new Intl.NumberFormat('zh-CN', {
style: 'currency',
currency: currency || 'CNY'
}).format(amount);
},
generateId: function() {
return Date.now().toString(36) + Math.random().toString(36).substr(2);
},
debounce: function(func, wait) {
var timeout;
return function executedFunction() {
var context = this;
var args = arguments;
var later = function() {
timeout = null;
func.apply(context, args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
}
};
})();
var UserModule = (function(utils) {
// 依赖工具模块
var users = [];
var currentUser = null;
function validateUser(user) {
return user && user.name && user.email;
}
function createUser(userData) {
if (!validateUser(userData)) {
throw new Error("用户数据无效");
}
return {
id: utils.generateId(),
name: userData.name,
email: userData.email,
createdAt: new Date(),
lastLogin: null
};
}
return {
addUser: function(userData) {
var user = createUser(userData);
users.push(user);
console.log(`用户 ${user.name} 已添加,ID: ${user.id}`);
return user;
},
login: function(email) {
var user = users.find(u => u.email === email);
if (user) {
user.lastLogin = new Date();
currentUser = user;
console.log(`用户 ${user.name} 登录成功`);
return true;
}
return false;
},
getCurrentUser: function() {
if (!currentUser) return null;
return {
...currentUser,
formattedCreatedAt: utils.formatDate(currentUser.createdAt),
formattedLastLogin: currentUser.lastLogin ?
utils.formatDate(currentUser.lastLogin) : '从未登录'
};
},
getUserList: function() {
return users.map(user => ({
id: user.id,
name: user.name,
email: user.email,
createdAt: utils.formatDate(user.createdAt)
}));
},
logout: function() {
if (currentUser) {
console.log(`用户 ${currentUser.name} 已登出`);
currentUser = null;
}
}
};
})(UtilsModule); // 注入依赖
console.log("=== 模块依赖示例 ===");
UserModule.addUser({ name: "张三", email: "zhang@example.com" });
UserModule.addUser({ name: "李四", email: "li@example.com" });
UserModule.login("zhang@example.com");
console.log("当前用户:", UserModule.getCurrentUser());
console.log("用户列表:", UserModule.getUserList());揭示模块模式是经典模块模式的改进版本,所有方法都定义为私有函数,然后选择性地暴露。
// 🎉 揭示模块模式基本结构
var RevealingModule = (function() {
// 私有变量
var privateVar = "私有变量";
var publicVar = "公共变量";
// 私有方法(所有方法都定义为私有)
function privateMethod() {
console.log("私有方法被调用");
return privateVar;
}
function publicMethod1() {
console.log("公共方法1被调用");
return privateMethod();
}
function publicMethod2() {
console.log("公共方法2被调用");
return publicVar;
}
function setPublicVar(value) {
publicVar = value;
console.log("公共变量已更新为:", value);
}
function getPrivateVar() {
return privateVar;
}
// 揭示公共接口
return {
// 映射到内部方法
method1: publicMethod1,
method2: publicMethod2,
setVar: setPublicVar,
getVar: getPrivateVar,
// 直接暴露变量
publicVariable: publicVar
};
})();
console.log("=== 揭示模块模式示例 ===");
console.log(RevealingModule.method1()); // 私有变量
RevealingModule.setVar("新值");
console.log(RevealingModule.getVar()); // 私有变量(不会改变)
// 🎉 揭示模块模式的高级应用
var AdvancedRevealingModule = (function() {
// 私有状态
var state = {
data: [],
currentIndex: -1,
isLoading: false,
error: null
};
var config = {
maxItems: 100,
autoSave: true,
debugMode: false
};
// 私有工具方法
function log(message, level) {
if (config.debugMode) {
console.log(`[${level}] ${new Date().toISOString()}: ${message}`);
}
}
function validateItem(item) {
return item && typeof item === 'object' && item.id;
}
function findItemIndex(id) {
return state.data.findIndex(item => item.id === id);
}
function saveToStorage() {
if (config.autoSave) {
try {
localStorage.setItem('moduleData', JSON.stringify(state.data));
log('Data saved to localStorage', 'INFO');
} catch (error) {
log('Failed to save data: ' + error.message, 'ERROR');
}
}
}
function loadFromStorage() {
if (config.autoSave) {
try {
var saved = localStorage.getItem('moduleData');
if (saved) {
state.data = JSON.parse(saved);
log('Data loaded from localStorage', 'INFO');
}
} catch (error) {
log('Failed to load data: ' + error.message, 'ERROR');
}
}
}
// 核心业务方法
function addItem(item) {
if (!validateItem(item)) {
state.error = "Invalid item data";
log('Attempted to add invalid item', 'ERROR');
return false;
}
if (state.data.length >= config.maxItems) {
state.error = "Maximum items limit reached";
log('Maximum items limit reached', 'WARN');
return false;
}
var existingIndex = findItemIndex(item.id);
if (existingIndex !== -1) {
state.error = "Item with this ID already exists";
log(`Item with ID ${item.id} already exists`, 'WARN');
return false;
}
state.data.push({
...item,
createdAt: new Date(),
updatedAt: new Date()
});
state.currentIndex = state.data.length - 1;
state.error = null;
log(`Item ${item.id} added successfully`, 'INFO');
saveToStorage();
return true;
}
function removeItem(id) {
var index = findItemIndex(id);
if (index === -1) {
state.error = "Item not found";
log(`Item with ID ${id} not found`, 'WARN');
return false;
}
state.data.splice(index, 1);
state.currentIndex = state.data.length > 0 ? 0 : -1;
state.error = null;
log(`Item ${id} removed successfully`, 'INFO');
saveToStorage();
return true;
}
function updateItem(id, updates) {
var index = findItemIndex(id);
if (index === -1) {
state.error = "Item not found";
return false;
}
Object.assign(state.data[index], updates, {
updatedAt: new Date()
});
state.error = null;
log(`Item ${id} updated successfully`, 'INFO');
saveToStorage();
return true;
}
function getItem(id) {
var item = state.data.find(item => item.id === id);
if (!item) {
state.error = "Item not found";
return null;
}
state.error = null;
return { ...item }; // 返回副本
}
function getAllItems() {
return state.data.map(item => ({ ...item })); // 返回副本数组
}
function clearAllItems() {
state.data = [];
state.currentIndex = -1;
state.error = null;
log('All items cleared', 'INFO');
saveToStorage();
}
function getStats() {
return {
totalItems: state.data.length,
currentIndex: state.currentIndex,
hasError: !!state.error,
lastError: state.error,
isLoading: state.isLoading
};
}
function updateConfig(newConfig) {
Object.assign(config, newConfig);
log('Configuration updated', 'INFO');
}
function getConfig() {
return { ...config }; // 返回副本
}
function initialize() {
log('Module initializing', 'INFO');
loadFromStorage();
log('Module initialized', 'INFO');
}
function destroy() {
log('Module destroying', 'INFO');
saveToStorage();
state.data = [];
state.currentIndex = -1;
state.error = null;
log('Module destroyed', 'INFO');
}
// 初始化
initialize();
// 揭示公共接口
return {
// CRUD操作
add: addItem,
remove: removeItem,
update: updateItem,
get: getItem,
getAll: getAllItems,
clear: clearAllItems,
// 状态和配置
getStats: getStats,
getConfig: getConfig,
updateConfig: updateConfig,
// 生命周期
init: initialize,
destroy: destroy
};
})();
console.log("=== 高级揭示模块模式示例 ===");
AdvancedRevealingModule.updateConfig({ debugMode: true });
AdvancedRevealingModule.add({ id: 1, name: "项目1", type: "task" });
AdvancedRevealingModule.add({ id: 2, name: "项目2", type: "note" });
console.log("统计信息:", AdvancedRevealingModule.getStats());
console.log("所有项目:", AdvancedRevealingModule.getAll());命名空间模式用于组织大型应用的模块结构,避免全局变量冲突。
// 🎉 基本命名空间模式
var MyApp = MyApp || {};
// 创建命名空间
MyApp.Utils = MyApp.Utils || {};
MyApp.Models = MyApp.Models || {};
MyApp.Views = MyApp.Views || {};
MyApp.Controllers = MyApp.Controllers || {};
// 工具命名空间
MyApp.Utils.String = (function() {
return {
capitalize: function(str) {
return str.charAt(0).toUpperCase() + str.slice(1);
},
truncate: function(str, length) {
return str.length > length ? str.slice(0, length) + '...' : str;
},
slugify: function(str) {
return str.toLowerCase()
.replace(/[^\w\s-]/g, '')
.replace(/[\s_-]+/g, '-')
.replace(/^-+|-+$/g, '');
}
};
})();
MyApp.Utils.Array = (function() {
return {
unique: function(arr) {
return [...new Set(arr)];
},
chunk: function(arr, size) {
var chunks = [];
for (var i = 0; i < arr.length; i += size) {
chunks.push(arr.slice(i, i + size));
}
return chunks;
},
shuffle: function(arr) {
var shuffled = [...arr];
for (var i = shuffled.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
[shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]];
}
return shuffled;
}
};
})();
// 模型命名空间
MyApp.Models.User = (function() {
var users = [];
var currentId = 1;
function User(data) {
this.id = currentId++;
this.name = data.name;
this.email = data.email;
this.createdAt = new Date();
this.updatedAt = new Date();
}
User.prototype.update = function(data) {
Object.assign(this, data, { updatedAt: new Date() });
};
User.prototype.toJSON = function() {
return {
id: this.id,
name: this.name,
email: this.email,
createdAt: this.createdAt,
updatedAt: this.updatedAt
};
};
return {
create: function(data) {
var user = new User(data);
users.push(user);
return user;
},
findById: function(id) {
return users.find(user => user.id === id);
},
findByEmail: function(email) {
return users.find(user => user.email === email);
},
getAll: function() {
return users.map(user => user.toJSON());
},
remove: function(id) {
var index = users.findIndex(user => user.id === id);
if (index !== -1) {
return users.splice(index, 1)[0];
}
return null;
}
};
})();
// 控制器命名空间
MyApp.Controllers.UserController = (function(UserModel, StringUtils) {
return {
createUser: function(userData) {
try {
// 数据验证和处理
if (!userData.name || !userData.email) {
throw new Error("姓名和邮箱是必需的");
}
userData.name = StringUtils.capitalize(userData.name.trim());
userData.email = userData.email.trim().toLowerCase();
// 检查邮箱是否已存在
if (UserModel.findByEmail(userData.email)) {
throw new Error("邮箱已存在");
}
var user = UserModel.create(userData);
console.log("用户创建成功:", user.toJSON());
return { success: true, user: user.toJSON() };
} catch (error) {
console.error("创建用户失败:", error.message);
return { success: false, error: error.message };
}
},
getUserList: function() {
var users = UserModel.getAll();
console.log("获取用户列表,共", users.length, "个用户");
return { success: true, users: users };
},
deleteUser: function(id) {
var user = UserModel.remove(id);
if (user) {
console.log("用户删除成功:", user.toJSON());
return { success: true, user: user.toJSON() };
} else {
console.log("用户不存在:", id);
return { success: false, error: "用户不存在" };
}
}
};
})(MyApp.Models.User, MyApp.Utils.String);
// 🎉 深层命名空间创建工具
MyApp.namespace = function(ns) {
var parts = ns.split('.');
var parent = MyApp;
for (var i = 0; i < parts.length; i++) {
if (typeof parent[parts[i]] === 'undefined') {
parent[parts[i]] = {};
}
parent = parent[parts[i]];
}
return parent;
};
// 使用命名空间工具
MyApp.namespace('Features.Dashboard.Widgets');
MyApp.Features.Dashboard.Widgets.Chart = (function() {
return {
render: function(data) {
console.log("渲染图表:", data);
}
};
})();
console.log("=== 命名空间模式示例 ===");
console.log(MyApp.Utils.String.capitalize("hello world"));
console.log(MyApp.Utils.Array.unique([1, 2, 2, 3, 3, 4]));
var result1 = MyApp.Controllers.UserController.createUser({
name: "张三",
email: "zhang@example.com"
});
var result2 = MyApp.Controllers.UserController.createUser({
name: "李四",
email: "li@example.com"
});
console.log(MyApp.Controllers.UserController.getUserList());单例模式确保一个类只有一个实例,并提供全局访问点。
// 🎉 基本单例模式
var Singleton = (function() {
var instance;
function createInstance() {
// 私有变量和方法
var privateVar = "私有变量";
var privateCounter = 0;
return {
publicMethod: function() {
return privateVar;
},
increment: function() {
privateCounter++;
return privateCounter;
},
getCount: function() {
return privateCounter;
}
};
}
return {
getInstance: function() {
if (!instance) {
instance = createInstance();
}
return instance;
}
};
})();
// 测试单例
var singleton1 = Singleton.getInstance();
var singleton2 = Singleton.getInstance();
console.log("=== 单例模式示例 ===");
console.log("是否为同一实例:", singleton1 === singleton2); // true
singleton1.increment();
console.log("singleton2的计数:", singleton2.getCount()); // 1
// 🎉 应用配置单例
var AppConfig = (function() {
var instance;
function createConfig() {
var config = {
apiUrl: "https://api.example.com",
version: "1.0.0",
debug: false,
features: {
userManagement: true,
analytics: false,
notifications: true
}
};
var listeners = [];
return {
get: function(key) {
return key ? config[key] : { ...config };
},
set: function(key, value) {
var oldValue = config[key];
config[key] = value;
// 通知监听器
listeners.forEach(listener => {
listener(key, value, oldValue);
});
},
update: function(updates) {
Object.assign(config, updates);
// 通知监听器
listeners.forEach(listener => {
listener('bulk_update', updates, null);
});
},
addListener: function(callback) {
listeners.push(callback);
},
removeListener: function(callback) {
var index = listeners.indexOf(callback);
if (index !== -1) {
listeners.splice(index, 1);
}
},
reset: function() {
config = {
apiUrl: "https://api.example.com",
version: "1.0.0",
debug: false,
features: {
userManagement: true,
analytics: false,
notifications: true
}
};
}
};
}
return {
getInstance: function() {
if (!instance) {
instance = createConfig();
}
return instance;
}
};
})();
// 使用配置单例
var config = AppConfig.getInstance();
config.addListener(function(key, newValue, oldValue) {
console.log(`配置变更: ${key} = ${newValue} (原值: ${oldValue})`);
});
console.log("=== 配置单例示例 ===");
console.log("当前配置:", config.get());
config.set('debug', true);
config.update({ version: "1.1.0", features: { analytics: true } });
// 🎉 日志管理单例
var Logger = (function() {
var instance;
function createLogger() {
var logs = [];
var maxLogs = 1000;
var levels = {
DEBUG: 0,
INFO: 1,
WARN: 2,
ERROR: 3
};
var currentLevel = levels.INFO;
function formatMessage(level, message, data) {
return {
timestamp: new Date(),
level: level,
message: message,
data: data || null,
id: Date.now() + Math.random()
};
}
function addLog(level, message, data) {
if (levels[level] >= currentLevel) {
var logEntry = formatMessage(level, message, data);
logs.push(logEntry);
// 限制日志数量
if (logs.length > maxLogs) {
logs.shift();
}
// 输出到控制台
var consoleMethod = level.toLowerCase();
if (console[consoleMethod]) {
console[consoleMethod](`[${level}] ${message}`, data || '');
}
return logEntry;
}
}
return {
debug: function(message, data) {
return addLog('DEBUG', message, data);
},
info: function(message, data) {
return addLog('INFO', message, data);
},
warn: function(message, data) {
return addLog('WARN', message, data);
},
error: function(message, data) {
return addLog('ERROR', message, data);
},
setLevel: function(level) {
if (levels[level] !== undefined) {
currentLevel = levels[level];
}
},
getLogs: function(level) {
if (level) {
return logs.filter(log => log.level === level);
}
return [...logs];
},
clearLogs: function() {
logs = [];
},
getStats: function() {
var stats = {};
Object.keys(levels).forEach(level => {
stats[level] = logs.filter(log => log.level === level).length;
});
return {
total: logs.length,
byLevel: stats,
currentLevel: Object.keys(levels)[currentLevel]
};
}
};
}
return {
getInstance: function() {
if (!instance) {
instance = createLogger();
}
return instance;
}
};
})();
// 使用日志单例
var logger = Logger.getInstance();
console.log("=== 日志单例示例 ===");
logger.info("应用启动");
logger.warn("这是一个警告");
logger.error("这是一个错误", { code: 500, details: "服务器错误" });
console.log("日志统计:", logger.getStats());通过本节JavaScript模块模式详解的学习,你已经掌握:
A: 经典模块模式在返回对象中直接定义方法,揭示模块模式先定义所有方法为私有,然后选择性暴露,后者更清晰。
A: 当需要确保全局只有一个实例时使用,如配置管理、日志系统、缓存管理等场景。
A: 通过创建嵌套的对象结构,将相关功能组织在特定命名空间下,避免全局变量冲突。
A: 虽然ES6模块提供了更好的解决方案,但理解模块模式有助于理解模块化思想和维护旧代码。
A: 根据项目需求选择:简单功能用基本模块模式,复杂逻辑用揭示模块模式,大型项目用命名空间模式。
// 问题:模块间循环依赖
// 解决:重新设计模块结构或使用事件系统
// ❌ 循环依赖问题
var ModuleA = (function(ModuleB) {
// ModuleA依赖ModuleB,但ModuleB还未定义
})(ModuleB);
// ✅ 解决方案:延迟依赖注入
var ModuleA = (function() {
var moduleB;
return {
setModuleB: function(mb) {
moduleB = mb;
},
useModuleB: function() {
if (moduleB) {
return moduleB.someMethod();
}
}
};
})();// 问题:模块持有不必要的引用
// 解决:及时清理引用和使用弱引用
// ❌ 可能的内存泄漏
var ProblematicModule = (function() {
var cache = {}; // 永远不清理的缓存
return {
addToCache: function(key, value) {
cache[key] = value;
}
};
})();
// ✅ 解决方案:提供清理方法
var SafeModule = (function() {
var cache = {};
return {
addToCache: function(key, value) {
cache[key] = value;
},
clearCache: function() {
cache = {};
}
};
})();"模块模式是JavaScript代码组织的重要方法,掌握不同的模块模式能让你写出更清晰、更可维护的代码。理解模块化思想,为学习现代模块系统打下坚实基础!"