Skip to content

Commit 8dd6054

Browse files
committed
2019.02.25
1 parent 00b286d commit 8dd6054

2 files changed

Lines changed: 147 additions & 0 deletions

File tree

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
### 一、单体模式(Singleton)
2+
#### 1.概念介绍
3+
**单体模式**的思想在于**保证一个特定类仅有一个实例**,即不管使用这个类创建多少个新对象,都会得到**与第一次创建的对象完全相同**
4+
5+
它让我们能将代码组织成一个逻辑单元,并可以通过单一变量进行访问。
6+
7+
单体模式有以下优点:
8+
* 用来划分命名空间,减少全局变量数量。
9+
* 使代码组织的更一致,提高代码阅读性和维护性。
10+
* 只能被实例化一次。
11+
12+
但在JavaScript中没有类,只有对象。当我们创建一个新对象,它都是个新的单体,因为JavaScript中永远不会有完全相等的对象,除非它们是同一个对象。
13+
因此,**我们每次使用对象字面量创建对象的时候,实际上就是在创建一个单例**
14+
```js
15+
let a1 = { name : 'leo' };
16+
let a2 = { name : 'leo' };
17+
a1 === a2; // false
18+
a1 == a2; // false
19+
```
20+
21+
这里需要注意,单体模式有个条件,是该对象能被实例化,比如下面这样就不是单体模式,因为它不能被实例化:
22+
```js
23+
let a1 = {
24+
b1: 1, b2: 2,
25+
m1: function(){
26+
return this.b1;
27+
},
28+
m2: function(){
29+
return this.b2;
30+
}
31+
}
32+
new a1(); // Uncaught TypeError: a1 is not a constructor
33+
```
34+
下面展示一个单体模式的基本结构:
35+
```js
36+
let Singleton = function (name){
37+
this.name = name;
38+
this.obj = null;
39+
}
40+
Singleton.prototype.getName = function(){
41+
return this.name;
42+
}
43+
function getObj(name){
44+
return this.obj || (this.obj = new Singleton(name));
45+
}
46+
let g1 = getObj('leo');
47+
let g2 = getObj('pingan');
48+
g1 === g2; // true
49+
g1 == g2; // true
50+
g1.getName(); // 'leo'
51+
g2.getName(); // 'leo'
52+
```
53+
从这里可以看出,单体模式只能实例化一次,后面再调用的话,都是使用第一次实例化的结果。
54+
55+
#### 2.应用场景
56+
单例模式只允许实例化一次,能提高对象访问速度并且节约内存,通常被用于下面场景:
57+
* 需要频繁创建再销毁的对象,或频繁使用的对象:如:弹窗,文件;
58+
* 常用的工具类对象;
59+
* 常用的资源消耗大的对象;
60+
61+
#### 3.实现弹框案例
62+
这里我们要用单体模式,创建一个弹框,大概需要实现:元素值创建一次,使用的时候直接调用。
63+
因此我们这么做:
64+
```js
65+
let create = (() => {
66+
let div;
67+
return () => {
68+
if(!div){
69+
div = document.createElement('div');
70+
div.innderHTML = '我是leo创建的弹框';
71+
div.style.display = 'none';
72+
div.setAttribute("id", "leo");
73+
document.body.appendChild(div);
74+
}
75+
return div;
76+
}
77+
})();
78+
// 触发事件
79+
document.getElementById('otherBtn').onclick = () => {
80+
let first = create();
81+
first.style.display = 'block';
82+
}
83+
```
84+
85+
#### 4.使用new操作符
86+
由于JavaScript中没有类,但JavaScript有`new`语法来用构造函数创建对象,并可以使用这种方法实现单体模式。
87+
当使用同一个构造函数以`new`操作符创建多个对象,获得的是指向完全相同的对象的新指针。
88+
89+
通常我们使用`new`操作符创建单体模式的三种选择,让构造函数总返回最初的对象:
90+
* 使用全局对象来存储该实例(不推荐,容易全局污染)。
91+
* 使用静态属性存储该实例,无法保证该静态属性的私有性。
92+
```js
93+
function Leo(name){
94+
if(typeof Leo.obj === 'object'){
95+
return Leo.obj;
96+
}
97+
this.name = name;
98+
Leo.obj = this;
99+
return this;
100+
}
101+
let a1 = new Leo('leo');
102+
let a2 = new Leo('pingan');
103+
a1 === a2 ; // true
104+
a1 == a2 ; // true
105+
```
106+
唯一的缺点就是`obj`属性是公开的,容易被修改。
107+
108+
* 使用闭包将该实例包裹,保证实例是私有性并不会被外界修改。
109+
110+
我们这通过重写上面的方法,加入闭包:
111+
```js
112+
function Leo(name){
113+
let obj;
114+
this.name = name;
115+
obj = this; // 1.存储第一次创建的对象
116+
Leo = function(){ // 2.修改原来的构造函数
117+
return obj;
118+
}
119+
}
120+
let a1 = new Leo('leo');
121+
let a2 = new Leo('pingan');
122+
a1 === a2 ; // true
123+
a1 == a2 ; // true
124+
```
125+
当我们第一次调用构造函数,像往常一样返回this,而后面再调用的话,都将重写构造函数,并访问私有变量`obj`并返回。
126+
127+
128+
### 参考资料
129+
1. 《JavaScript Patterns》
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
## 本节目录
2+
3+
* [一、单体模式](#一单体模式)
4+
* [二、工厂模式](#二工厂模式)
5+
* [三、迭代器模式](#三迭代器模式)
6+
* [四、装饰者模式](#四装饰者模式)
7+
* [五、策略模式](#五策略模式)
8+
* [六、外观模式](#六外观模式)
9+
* [七、代理模式](#七代理模式)
10+
* [八、中介者模式](#八中介者模式)
11+
* [九、观察者模式](#九观察者模式)
12+
13+
14+
设计模式是可重用的用于解决软件设计中一般问题的方案,学习好一些设计模式,不仅让我们站在巨人的肩膀上,获得前人所有的经验,保证我们以优雅的方式组织我们的代码,满足我们解决问题所需要的条件。
15+
16+
JavaScript是一种弱类型的、动态的、基于原型的语言,这使得它能很容易的实现一些设计模式。
17+
18+
本文我们将介绍九种常见的设计模式,看看在JavaScript中如何实现这些设计模式。

0 commit comments

Comments
 (0)