设计模式
观察者模式
两个角色
js
class Subject {
constructor(name) {
this.name = name
this.observers = []
}
add(observer) {
this.observers.push(observer)
}
notify() {
this.observers.forEach(observer => {
observer.update(this.name)
})
}
}
class Observer {
constructor(name) {
this.name = name
}
update(...args) {
console.log(`${args} updated, ${this.name}`)
}
}
const tv = new Subject("三体")
const you = new Observer("tom")
const me = new Observer("jack")
tv.add(you)
tv.add(me)
tv.notify()
发布订阅模式
三个角色:发布者、调度中心、订阅者
js
// 发布者
class Publisher {
constructor(name) {
this.name = name
this.eventChannel = null
}
connect(eventChannel) {
this.eventChannel = eventChannel
}
notify(type, ...args) {
this.eventChannel.notify(type, ...args)
}
}
// 通知者
class EventChannel {
constructor(name) {
this.name = name
this.subscribers = {}
}
subscribe(type, cb) {
if (!this.subscribers[type]) this.subscribers[type] = []
this.subscribers[type].push(cb)
}
unsubscribe(type, cb) {
const cbs = this.subscribers[type]
if (cbs && cbs.length) {
cbs.splice(cbs.findIndex(i => i === cb), 1)
console.log('取消订阅成功')
}
}
notify(type, ...args) {
const cbs = this.subscribers[type]
if (cbs && cbs.length) {
cbs.forEach(element => {
element.update(type, ...args)
})
} else {
console.log("该事件无订阅者")
}
}
}
// 订阅者
class Subscriber {
constructor(name) {
this.name = name
}
update(type, ...args) {
console.log(`${this.name} 收到了 ${type}, ${args}`)
}
}
const pub = new Publisher("任务中心")
const ec = new EventChannel("事件中心")
pub.connect(ec)
const user1 = new Subscriber("tom")
const user2 = new Subscriber("jack")
ec.subscribe("warTask", user1)
ec.subscribe("warTask", user2)
pub.notify("warTask", 100)
pub.notify("normalTask")
ec.unsubscribe("warTask", user1)
pub.notify("warTask", 200)
单例模式
保证一个类只能被实例一次主题
js
class Single {
static instance = null
constructor() {
this.state = "on"
}
static open() {
this.getInstance()
this.state = "on"
return this.instance
}
static close() {
this.getInstance()
this.state = "off"
return this.instance
}
static getInstance() {
this.instance ? this.instance : new Single()
}
}
const foo = Single.open()
const bar = Single.close()
console.log(foo === bar)
装饰器模式
在原本对象上装饰拓展功能
js
class Foo {
constructor() {}
say() {
console.log("Hi")
}
}
class Bar {
constructor(foo) {
this.foo = foo
}
say() {
this.foo.say()
}
hear() {
console.log("Hear")
}
read() {
console.log("read")
}
}
const foo = new Foo()
const bar = new Bar(foo)
bar.say()
bar.read()
代理模式
代理目标对象,以拦截操作,增加功能
js
const me = {
name: 'tom',
age: 18
}
const myLawyer = new Proxy(me, {
get: (me, property, receiver) => {
console.log(`receiver is proxy: ${receiver === proxy}`); // 输出 "receiver is proxy: true"
if (property === 'name') {
return 'lawyer'
}
return me[property]
// return Reflect.get(target, property, receiver); // 用Reflect最好
},
set(me, property, value, receiver) {
console.log(`you set ${property} to ${value} just now`, me, receiver)
me[property] = value
// return Reflect.set(target, property, receiver); // 用Reflect最好
return true
}
})
console.log(myLawyer.name) // lawyer
myLawyer.age = 19 // you set age to 19 just now
console.log(myLawyer.age) // 19
Reflect
引伸下
Reflect.get(target, property, receiver) 是 JavaScript 中的一个反射操作,用于获取一个对象的属性值。这个方法接受三个参数:
- target:目标对象,即要获取属性值的对象。
- property:要获取的属性的名称。
- receiver:在获取属性值时作为 this 的值。 如果 property 是一个访问器属性(即它是一个 getter),那么 receiver 将被用作 getter 函数内部的 this 值。如果 property 是一个数据属性,那么 receiver 参数将被忽略。
在 Proxy 对象的 get 陷阱中使用 Reflect.get 可以确保原始对象的行为被正确地复制,包括正确地处理访问器属性。例如:
js
const obj = {
get foo() {
return this.bar;
},
bar: 1
};
const proxy = new Proxy(obj, {
get(target, property, receiver) {
return Reflect.get(target, property, receiver);
}
});
console.log(proxy.foo); // 输出 1