深色模式
设计模式不是背面试题用的,是真实项目里解决特定问题的工具。记录三个我实际用到过的模式。
观察者模式(发布/订阅)
用于解耦:A 不需要直接知道 B,只需要发布事件,B 自己订阅。
javascript
class EventEmitter {
constructor() {
this._events = {};
}
on(event, listener) {
if (!this._events[event]) {
this._events[event] = [];
}
this._events[event].push(listener);
return this;
}
off(event, listener) {
if (!this._events[event]) return;
this._events[event] = this._events[event].filter((l) => l !== listener);
return this;
}
emit(event, ...args) {
if (!this._events[event]) return;
this._events[event].forEach((listener) => listener(...args));
return this;
}
once(event, listener) {
const wrapper = (...args) => {
listener(...args);
this.off(event, wrapper);
};
return this.on(event, wrapper);
}
}
// 使用
const bus = new EventEmitter();
bus.on("data:loaded", (data) => console.log("数据加载完成", data));
bus.emit("data:loaded", { list: [] });Vue 的 $on/$emit 本质就是这个模式。
策略模式
把多个 if/else 分支替换成策略对象,让代码更易扩展。
javascript
// 糟糕写法:if/else 不断增长
function calculateDiscount(type, price) {
if (type === "vip") {
return price * 0.8;
} else if (type === "svip") {
return price * 0.6;
} else if (type === "newUser") {
return price - 10;
} else {
return price;
}
}
// 策略模式:每种策略单独定义
const discountStrategies = {
vip: (price) => price * 0.8,
svip: (price) => price * 0.6,
newUser: (price) => price - 10,
default: (price) => price,
};
function calculateDiscount(type, price) {
const strategy = discountStrategies[type] || discountStrategies.default;
return strategy(price);
}
// 加新折扣类型只需加一个属性,不动原有逻辑
discountStrategies.employee = (price) => price * 0.5;在前端表单验证里也常用:
javascript
const validators = {
required: (value) => !!value || "不能为空",
email: (value) =>
/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value) || "邮箱格式不正确",
minLength: (min) => (value) => value.length >= min || `最少${min}个字符`,
};代理模式
在访问某个对象之前加一层代理,用于缓存、权限控制、懒加载等。
javascript
// 缓存代理:避免重复计算
function createCacheProxy(fn) {
const cache = new Map();
return function (...args) {
const key = JSON.stringify(args);
if (cache.has(key)) {
console.log("命中缓存");
return cache.get(key);
}
const result = fn.apply(this, args);
cache.set(key, result);
return result;
};
}
const expensiveCalc = (n) => {
// 假设是很慢的计算
return n * n;
};
const cachedCalc = createCacheProxy(expensiveCalc);
cachedCalc(10); // 计算
cachedCalc(10); // 命中缓存,直接返回
// ES6 Proxy:更强大
const handler = {
get(target, key) {
console.log(`访问了 ${String(key)}`);
return Reflect.get(target, key);
},
set(target, key, value) {
if (typeof value !== "number") {
throw new TypeError(`${String(key)} 必须是数字`);
}
return Reflect.set(target, key, value);
},
};
const validator = new Proxy({}, handler);
validator.age = 25; // 正常
validator.age = "25"; // TypeError小结
- 观察者模式:解耦事件发布和订阅,Vue 的 $on/$emit 就是它
- 策略模式:消除 if/else,把分支逻辑变成可扩展的策略对象
- 代理模式:在访问对象前加一层控制,用于缓存、验证、日志等
- 设计模式是工具,不要为了用而用