写JavaScript时,很多人一开始都是想到哪写到哪。比如做个购物车功能,点一下加商品,再点一下减商品,代码堆得越来越多,改一个地方可能整个功能就出问题。其实这些问题,早就有成熟的解决思路了——这就是设计模式。
单例模式:全局只用一个实例
有些东西不需要多个,比如页面里的登录弹窗。不管你从哪个按钮点开,都应该是同一个弹窗实例。单例模式就是确保一个类只有一个实例,并提供全局访问入口。
const LoginModal = (function() {
let instance;
function createInstance() {
const div = document.createElement('div');
div.innerHTML = '登录窗口';
div.style.display = 'none';
document.body.appendChild(div);
return div;
}
return {
getInstance: function() {
if (!instance) {
instance = createInstance();
}
return instance;
}
};
})();
// 使用
const modal1 = LoginModal.getInstance();
const modal2 = LoginModal.getInstance();
console.log(modal1 === modal2); // true,同一个实例
观察者模式:消息通知机制
就像你关注了一个公众号,有更新就会收到推送。前端里常见的事件监听其实就是观察者模式的应用。比如用户登录成功后,头像、菜单、通知栏都要更新状态,但你不希望每个模块都去主动查登录状态。
class EventBus {
constructor() {
this.events = {};
}
on(event, callback) {
if (!this.events[event]) {
this.events[event] = [];
}
this.events[event].push(callback);
}
emit(event, data) {
if (this.events[event]) {
this.events[event].forEach(callback => callback(data));
}
}
}
// 使用
const bus = new EventBus();
bus.on('login', user => console.log('欢迎 ' + user));
bus.on('login', () => updateHeader());
bus.emit('login', '张三');
工厂模式:统一创建对象
假设你在做一个表单验证功能,有文本框、邮箱、手机号等不同类型的校验规则。如果每个都手动 new 一个对应的类,代码会很乱。工厂模式可以帮你根据类型自动创建对应的实例。
class Validator {
validate(value) {
throw new Error('子类必须实现validate方法');
}
}
class EmailValidator extends Validator {
validate(email) {
return /\S+@\S+\.\S+/.test(email);
}
}
class PhoneValidator extends Validator {
validate(phone) {
return /^1[3-9]\d{9}$/.test(phone);
}
}
class ValidatorFactory {
static create(type) {
switch(type) {
case 'email':
return new EmailValidator();
case 'phone':
return new PhoneValidator();
default:
throw new Error('不支持的类型');
}
}
}
// 使用
const emailValidator = ValidatorFactory.create('email');
console.log(emailValidator.validate('test@example.com')); // true
这些模式不是炫技,而是为了解决实际问题。当你发现代码越来越难维护,或者重复逻辑太多时,不妨想想有没有更清晰的组织方式。设计模式就像工具箱里的扳手、螺丝刀,用对了地方,修起“bug”来事半功倍。