1、单例模式
1 <!DOCTYPE html>
2 <html lang="en">
3 <head>
4 <meta charset="UTF-8">
5 <meta name="viewport" content="width=device-width, initial-scale=1.0">
6 <title>单例模式</title>
7 </head>
8 <body>
9
10 </body>
11 <script>
12 /*
13 单例模式:
14 单:单一、一个
15 例:实例
16 一个构造函数一生只能有一个实例 =>不管你 new 多少次,都是这一个实例
17 应用:
18 自定义弹出层
19 核心代码:
20 let instance = null;
21 function singleTon(){
22 if(!instance) instance = 实例对象;
23 return instance
24 }
25 问题:
26 1、书写代码的时候和构造函数已经没有关系
27 2、new 关键字没有了
28 */
29
30 function Person(){
31 this.name = 'Jack';
32 }
33
34 let instance = null;
35
36 function singleTon(){
37 if(!instance) instance = new Person();
38 return instance
39 }
40 //
41 const p1 = singleTon();
42 const p2 = singleTon();
43
44 console.log(p1,p2);
45 console.log(p1===p2);
46
47 </script>
48 </html>
2、单例模式改进
1 <!DOCTYPE html>
2 <html lang="en">
3
4 <head>
5 <meta charset="UTF-8">
6 <meta name="viewport" content="width=device-width, initial-scale=1.0">
7 <title>单例模式改造</title>
8 </head>
9
10 <body>
11
12 </body>
13 <script>
14 /*
15 单例模式改造
16 我需要把 instance 变量保存下来
17 singleTon 是一个函数,里面可以判断,可以返回
18 以闭包的形式来执行一段代码
19 为了保存构造函数,把他也写进闭包函数里面
20 如果你觉得需要使用 new ,那么你就直接写
21 */
22
23
24 const Person = (function () {
25 // 真是构造函数体
26 function Person(name,age,gender) {
27 this.name = name;
28 this.age = age;
29 this.gender = gender;
30 }
31
32 Person.prototype.sayHi = function(){console.log('Hi')}
33
34 // 这个变量因为在一个不会被销毁的函数执行空间里面
35 // 所以会一直存在
36 let instance = null;
37 // 全局变量接收的是这个函数
38 return function singleTon(...arg) {
39 if (!instance) instance = new Person(...arg);
40 return instance
41 }
42 })()
43
44 const p1 = new Person('Jack',18,'男');
45 const p2 = new Person('rose',20,'女');
46
47 console.log(p1, p2);
48 console.log(p1 === p2);
49 </script>
50
51 </html>
3、观察者模式
1 <!DOCTYPE html>
2 <html lang="en">
3
4 <head>
5 <meta charset="UTF-8">
6 <meta name="viewport" content="width=device-width, initial-scale=1.0">
7 <title>观察者模式</title>
8 </head>
9
10 <body>
11
12 </body>
13 <script>
14 /*
15 观察者模式
16 例子:监控
17 我们坐在教室里面就是 被观察者
18 监控后面的老师,就是 观察者
19 当被观察者触发了一些条件的时候,观察者就会触发技能
20 观察者模式:监控一个 对象 的状态,一旦状态发生改变,马上触发技能
21 需要两个构造函数来实现
22 1、创建被观察者
23 属性,自己的状态
24 队列,记录都有谁观察着自己,数组[]
25 方法,能设置自己的状态,当我需要改变的时候,要触发这个方法改变状态
26 方法,添加观察者
27 方法,删除观察者
28 2、创建观察者
29 需要一个身份证明
30 需要一个技能
31 */
32
33 // 观察者构造函数
34 class Observer {
35 constructor(name, fn = () => { }) {
36 this.name = name;
37 this.fn = fn;
38 }
39 }
40
41 // 创建两个观察者
42 const bzr = new Observer('班主任', (state) => { console.log('因为:' + state + ',把你家长叫来') })
43 const njzr = new Observer('年纪主任', (state) => { console.log('因为:' + state + ',问你你是那个班的?') })
44 const xz = new Observer('校长', (state) => { console.log('因为:' + state + ',骂你的班主任') })
45
46 console.log(bzr, xz)
47
48 // 被观察者的构造函数
49 class Subject {
50 constructor(state) {
51 this.state = state;
52 // 数组用来保存观察着我的人
53 this.observers = [];
54 }
55
56 // 设置自己的状态
57 setState(val) {
58 this.state = val;
59 // 就需要把 我的所有观察者的技能都触发
60 // 遍历 this.observers 一次触发技能
61 this.observers.forEach(item => {
62 // item 就是每一个观察者,就是一个一个的对象
63 // console.log(item)
64 // 告诉他我改变成了什么状态
65 item.fn(this.state)
66 })
67 }
68
69 // 添加观察者
70 addObserver(obs) {
71 // 谁是观察者,就传递谁进来
72 // 判断一下,如果观察者已存在,就不添加了
73 // some()
74 // const res = this.observers.some(item => item === obs)
75 // find()
76 // const res = this.observers.find(item => item === obs)
77 // indexOf()
78 // const res = this.observers.indexOf(obs)
79 // filter()
80 // const res = this.observers.filter(item => item === obs)
81 this.observers = this.observers.filter(item => item !== obs)
82 // findIndex()
83 // const res = this.observers.findIndex(item => item === obs)
84 this.observers.push(obs);
85 }
86
87 // 删除观察者
88 delObserver(obs) {
89 // 把 obs 观察者删除
90 // 直接使用 filter 方法
91 this.observers.filter(item => item !== obs)
92 }
93 }
94
95 // 创建一个被观察者
96 const xiaoming = new Subject('学习');
97
98 // 给 xiaoming 添加一个观察者
99 xiaoming.addObserver(njzr);
100 xiaoming.addObserver(bzr);
101 xiaoming.addObserver(xz);
102
103 console.log(xiaoming);
104
105 // 创建一个被观察者
106 const xiaohong = new Subject('学习');
107
108 // 给 xiaoming 添加一个观察者
109 xiaoming.addObserver(bzr);
110 xiaoming.addObserver(xz);
111
112
113
114
115
116 </script>
117
118 </html>
4、发布订阅模式
1 <!DOCTYPE html>
2 <html lang="en">
3
4 <head>
5 <meta charset="UTF-8">
6 <meta name="viewport" content="width=device-width, initial-scale=1.0">
7 <title>发布订阅模式</title>
8 </head>
9
10 <body>
11
12 </body>
13 <script>
14 /*
15 发布订阅模式:
16 有一个对象,有人一直看着他
17 当这个对象发生变化的时候,第三方通知这个看着的人,触发技能
18 例子:买书
19 1、普通程序员买书
20 去书店,问,没有,回家
21 过一会再去,问,没有,回家
22 过一会再去,问,没有,回家
23 2、发布订阅的程序员
24 去书店,问,没有,留下一个联系方式给店员
25 一旦有了书,就会接到电话
26 触发技能买书
27 只需要一个构造函数
28 创建一个第三方店员的身份
29 我们的任务就是模拟一个 addEventListener()
30
31 分析构造函数
32 属性:消息队列
33 {
34 click:[fn1, fn2],
35 abc:[fn1, fn2, fn3]
36 }
37 方法:能向消息队列里面添加内容
38 方法:删除消息队列里面的内容
39 方法:触发消息队列里面的内容
40 */
41
42 // 创建一个第三方观察者构造函数
43 class Observer {
44 constructor() {
45 this.message = {}
46 }
47 // 1、向消息队列里面添加内容
48 on(type, fn) {
49 // type 我拜托你看着的行为
50 // fn 我要你在行为发生的时候做的事情
51 // 就应该把写着记录再消息队列
52 // 1、判断 message 里面有没有这个行为已经被注册过了
53 // 如果没有,我应该给你赋值一个这个行为,值赋值为[]
54 // 如果有,直接向数组里面添加就可以了。
55 if (!this.message[type]) {
56 // 表示消息队列里面还没有注册过
57 this.message[type] = []
58 }
59 // 直接进行 push
60 this.message[type].push(fn)
61 }
62 // 2、删除消息队列里面的内容
63 off(type, fn) {
64 // 判断 如果 fn 不存在,只有一个参数的情况
65 if (!fn) {
66 // 直接把这个事情取消掉
67 // 从 message 里面直接把 abc 成员删除掉,就好了
68 delete this.message[type]
69 return
70 }
71 // 代码能来到这里,表示 fn 存在
72 // 判断你是不是真的订阅过
73 if (!this.message[type]) return
74
75 // 你确实订阅过,就可以使用 filter 删除了
76 this.message[type] = this.message[type].filter(item => item !== fn)
77 }
78 // 3、触发消息队列
79 trigger(type) {
80 // 判断是不是有订阅过
81 if (!this.message[type]) return;
82
83 // 找到这个数组,把里面的每一个函数都触发
84 this.message[type].forEach(item => {
85 // item 就是每一个函数
86 item();
87 })
88 }
89 }
90
91 // 使用构造函数创建一个实例
92 const person1 = new Observer();
93
94 // 订阅
95 // 当你向拜托这个 person1 帮你观察一些内容的时候
96 // 告诉你一个行为,当行为出现的时候,告诉你干什么
97 person1.on('abc', handlerA);
98 person1.on('abc', handlerB);
99 person1.on('犀牛书', handlerC);
100
101
102 //取消订阅
103 // 告诉 person1 ,我这个事情不用你管了
104 // 1、我告诉你这个事情不用你管了
105 // person1.off('abc'); //把消息队列 里面属于 abc 的数组清空掉
106 // person1.off('a',handlerA) //告诉你 a 发生的时候,不用做 handlerA 这个事情了
107
108 // person1.off('c', handlerA);
109 // person1.off('abc', handlerA);
110
111 // 触发消息队列
112 // person1 这个人一旦触发 a 行为,就要把后面的所有事情处理函数执行掉
113 person1.trigger('abc');
114
115 console.log(person1)
116
117 function handlerA() { console.log('handlerA') }
118 function handlerB() { console.log('handlerB') }
119 function handlerC() { console.log('handlerC') }
120 function handlerD() { console.log('handlerD') }
121 function handlerE() { console.log('handlerE') }
122 function handlerF() { console.log('handlerF') }
123
124
125
126
127
128 </script>
129
130 </html>
5、策略模式
1 <!DOCTYPE html>
2 <html lang="en">
3
4 <head>
5 <meta charset="UTF-8">
6 <meta name="viewport" content="width=device-width, initial-scale=1.0">
7 <title>策略模式</title>
8 </head>
9
10 <body>
11
12 </body>
13 <script>
14 /*
15 策略模式:
16 + 一个问题匹配多个解决方案,不一定要用到那一个
17 + 而且有可能随时还会继续增加多个方案
18 例子:购物车结算
19 => 我们有好多种折扣计算方式
20 => 满 100 减 20
21 => 满 200 减 25
22 => 8 折
23 => 7 折
24
25 1、把我们的多种方案,以闭包的形式保存起来
26 + 按照传递进来的折扣和价格计算最终结果返回
27 2、留下添加和删除的折扣的接口
28 + 函数也是一个对象
29 + 可以把函数名当作一个对象,向里面添加一些成员
30 */
31
32 // 简单实现:接收两个参数:price type
33 // 一旦加一种折扣,就很麻烦
34 // function calcPrice(price, type) {
35 // if (type === '100_10') {
36 // price -= 30
37 // } else if (type === '200_25') {
38 // price -= 25
39 // } else if (type === '80%') {
40 // price *= 0.8
41 // } else {
42 // console.log('没有这种折扣')
43 // }
44 // return price
45 // }
46
47
48
49
50
51 // 1、暂时以闭包的形式把折扣方案保存下来
52 // const calcPrice = (function () {
53
54 // const sale = {
55 // '100_10': price => price -= 10,
56 // '200_25': price => price -= 25,
57 // '80%': price => price *= 0.8,
58 // }
59
60 // // 被 return 出去的函数,才是 calcPrice 本体
61 // return function calcPrice(price, type) {
62 // // 判断对象里面有没有这个折扣类型
63 // // 如果有,那么就执行
64 // // 如果没有,那么就告诉他没有这个折扣类型
65 // if (!sale[type]) return '没有这个折扣';
66
67 // // 找到 sale 里面指定的那个函数执行计算出结果,返回给外边
68 // return sale[type](price)
69 // }
70 // })()
71
72
73 // 2、留下添加和删除折扣的接口
74 const calcPrice = (function () {
75 const sale = {
76 '100_10': price => price -= 10,
77 '200_25': price => price -= 25,
78 '80%': price => price *= 0.8,
79 }
80
81 function calcPrice(price, type) {
82 if (!sale[type]) return '没有这个折扣';
83 return sale[type](price)
84 }
85
86 // 把函数当作一个对象,向里面添加一些成员
87 calcPrice.add = function (type, fn) {
88 // 专门用来添加折扣
89 // 判断这个折扣是不是存在
90 if (sale[type]) return '该折扣已经存在';
91
92 // 代码来到这里,表示折扣不存在
93 sale[type] = fn;
94 return '添加成功'
95 }
96
97 // 删除一个折扣
98 calcPrice.del = function (type) {
99 // 把对应的折扣删除掉
100 delete sale[type]
101 }
102
103 return calcPrice
104 })()
105
106 // 使用的时候
107 // 添加一个折扣
108 calcPrice.add('70%', function (price) { return price *= 0.7 })
109 const res = calcPrice(320, '70%')
110 console.dir(calcPrice)
111 console.dir(res)
112
113 // 删除一个折扣
114 calcPrice.del('100_10');
115 const res2 = calcPrice(320, '100_10');
116 console.log(res2)
117
118 // const res = calcPrice(320, '200_25');
119 // const res = calcPrice(320, '70%');
120 // console.log(res)
121
122
123
124
125
126
127 </script>
128
129 </html>
![]()