Javascript 设计模式之美

一、面向对象编程

二、创建型设计模式

一类处理对象创建的模式,通过某种方式控制对象的创建来避免基本对象创建时可能导致设计上的问题或增加设计上的复杂度。

1.简单工厂模式

静态工厂方法,由一个工厂对象决定创建某一种产品对象的实例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
//方式一、通过类实例化对象创建
var LoginAlert = function(text){
this.content = text;
}
LoginAlert.prototype.show = function(){
//显示alert
}
var LoginConfirm = function(text){
this.content = text;
}
LoginConfirm.prototype.show = function(){
//显示confirm
}
var LoginPrompt = function(text){
this.content = text;
}
LoginPrompt.prototype.show = function(){
//显示Prompt
}

var PopFactory = function(name){
switch(name){
case 'alert':
return new LoginAlert();
case 'confirm':
return new LoginConfirm();
case 'prompt':
return new LoginPrompt();
}
}

// 方法二 通过创建一个新对象然后包装增强其属性和功能来实现的
function createPop(type,text){
var o = new Object();
o.content = text;
o.show = function(){
// show
};
if(type==='alert'){
// alert
}
if(type==='prompt'){
// prompt
}
if(type==='confirm'){
// confirm
}
return o;
}
var usernamealert = createPop('alert','用户名只能是26个字母');

2.工厂方法模式

通过对产品类的抽象使其创建业务主要负责用于创建多累产品的实例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
var Factory = function(type,content){
if(this instanceof Factory){
var s = new this[type](content);
return s;
}else{
return new Factory(type,content);
}
}
Factory.prototype = {
Java:function(content){
//
},
Javascript:function(content){
//
},
UI:function(content){
this.content = content;
(function(content){
var div = document.createElement('div');
div.innerHTML = content;
div.style.border = '1px solid #ccc';
document.getElementById('container').appendChild(div);
})(content);
}
...
}
var data = [
{type:'Java',content:'...'},
{type:'Javascript',content:'...'},
{type:'UI',content:'...'},
]
for(var i = 6;i>=0;i--){
Factory(s[i].type,s[i].content);

}

3.抽象工厂模式

通过对类的工厂抽象使其业务用于对产品类簇的创建,而不负责创建某一类产品的实例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
var VehicleFactory = function(subType,supperType){
// 判断抽象工厂中是否有该抽象类
if(typeof VehicleFactory[subType] === 'function'){
function F(){}; //缓存类
F.prototype = new VehicleFactory[subType]();//继承父类属性和方法
subType.constructor = subType;//将子类constructor指向子类
subType.prototype = new F();//子类原型继承父类
}else{
throw new Error('未创建该抽象类');
}
}
// 小汽车抽像类
VehicleFactory.Car = function(){
this.type = 'car';
};
VehicleFactory.Car.prototype = {
getPrice:function(){
return new Error('抽象方法不能调用');
},
getSpeed:function(){
return new Error('抽象方法不能调用');
}
}
// 公交车抽像类
VehicleFactory.Car = function(){
this.type = 'bus';
};
VehicleFactory.Bus.prototype = {
getPrice:function(){
return new Error('抽象方法不能调用');
},
getSpeed:function(){
return new Error('抽象方法不能调用');
}
}
// 卡车抽像类
VehicleFactory.Truck = function(){
this.type = 'truck';
};
VehicleFactory.Car.prototype = {
getPrice:function(){
return new Error('抽象方法不能调用');
},
getSpeed:function(){
return new Error('抽象方法不能调用');
}
}

// 抽象工厂实现对CAR抽象类的继承
var BMW = function(price,speed){
this.price = price;
this.speed = speed;
}
VehicleFactory(BMW,'car');
BMW.prototype.getPrice = function(){
return this.price;
}
BMW.prototype.getSpeed = function(){
return this.speed;
}

4.建造者模式

Builder将一个复杂对象的构建层与其表示层相互分离。

  • 创建的对象是一个复合对象
  • 关心的是建造的过程
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
// 创建一位人类
var Human = function(param){
this.skill = param && param.skill || '保密';
this.hobby = param && param.hobby || '保密';
}
// 类人的原型方法
Human.prototype = {
getSkill:function(){
return this.skill;
},
getHobby:function(){
return this.hobby;
}
}
//实例化
var Named = function(name){
var that = this;
(function(name,that){
that.woleName = name;
if(name.indexOf(' ')>-1){
that.FirstName = name.slice(0,name.indexOf(' '));
that.SecondName = name.slice(name.indexOf(' '));
}
})(name,that);
}
var Work = funciton(work){
var that = this;
(function(work,that){
switch(work){
case 'code':
that.work = '工程师';
that.workDescript = 'programer';
case 'UI':
that.work = '设计师';
that.workDescript = 'designer';
default :
that.work = work;
that.workDescript = 'sorry';

}
})(work,that)
}
//更换期望职位
Work.prototype.changeWork = function(work){
this.work = work;
}
//添加职位描述
Work.prototype.changeDescript = function(setence){
this.changeDescript = setence;
}

创建一位应聘者

1
2
3
4
5
6
7
8
9
var Person = function(name,work){
var _person = new Human();
_person.name = new Named(name);
_person.work = new Work(work);
return _person;
}


var person = new Person('lee','code');

5.原型模式

Prototype用原型实例指向创建对象的类,使用于创建新的对象的类共享 原型对象的属性及方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
var LoopImages = function(imgArr,container){
this.imageArray = imgArr;
this.container = container;
}
LoopImages.prototype = {
createImage: fucntion(){
//
},
changeImage: fucntion(){
//
}
}
var SlideLoopImg = function(imgArr,container){
LoopImages.call(this,imgArr,container)
}
SlideLoopImg.prototype = new LoopImages();
// 重写继承
SlideLoopImg.prototype.changeImage = function(){
console.log("changeImage fn");
}
var FadeLoopImg = function(imgArr,container,arrow){
LoopImages.call(this,imgArr,container)
this.arrow = arrow;
}
FadeLoopImg.prototype = new LoopImages();
FadeLoopImg.prototype.changeImage = function(){
console.log("changeImage fn");
}


// 原型可以扩展
LoopImages.prototype.getImageLength = function(){
return this.imagesArray.length;
}
LoopImages.prototype.getContainer = function(){
return this.container;
}

6.单例模式

单体模式,只允许实例化一次的对象类。

命名空间,namespace

1
2
3
4
5
6
7
8
var Ming = {
g: function(id){
return document.getElementById(id);
},
css: function(id,key,value){
this.g(id).style[key] = value;
}
}

小型代码库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var A = {
Util:{
util_methods1 : function(){},
util_methods2 : function(){}
},
Tool:{
tool_methods1 : function(){},
tool_methods2 : function(){}
},
Ajax:{
get : function(){},
post : function(){}
}
}

无法修改的静态变量

1
2
3
4
5
6
7
8
9
10
11
12
var Conf = (function(){
var conf = {
NUM:1,
COUNT:100
}
return {
get:function(name){
return conf[name] ? conf[name] : null;
}
}
})
Conf.get('COUNT');

惰性单例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var LazySingle = function(){
var instance = null
function Single(){
return {
publicMethod : function(){},
publicProperty : '1.0'
}
}'
return function(){
if(!_instance){
_instance = Single();
}
return _instance;
}
}
//test
LazySingle().publickProperty; // 1.0

三、结构型设计模式

关注如何将类或对象组合成更大、更复杂的架构,以简化设计

1.外观模式

为一组复杂的子系统接口提供一个更高级的统一接口,使访问更容易。底层结构兼容性做统一的简化用户使用。

addEventListener && attachEvent

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 兼容模式
function addEvent(dom,type,fn){
if(dom.addEventListener){
dom.addEventListener(type,fn,false);
}else if(){
dom.attachEvent("on"+type,fn);
}else{
dom['on'+type] = fn;
}
}
// 这样就可以开始绑定事件了
var myInput = document.getElementById('myinput');
addEvent(myInput,'click',function(){
console.log('绑定的第一个事件');
})
addEvent(myInput,'click',function(){
console.log('绑定的第二个事件');
})

e.preventDefault && e.target

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// 获取事件对象
var getEvent = function(event){
return event || window.event;
}
// 获取元素
var getTarget = function(event){
var event = getEvent(event);
return event.target || event.srcElement;
}
// 阻止默认行为
var preventDefault = function(event){
var event = getEvent(event);
//非IE
if(event.preventDefault){
event.preventDefault();
}else{
//IE
event.returnValue = false;
}
}

//兼容模式开始了
document.onclick=function(e){
//阻止默认为行
preventDefault(e);
// 获取事件源目标对象
if(getTarget(e) !== document.getElementById('myInput')){
hideInputSug();
}
}

小型代码库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var A = {
g: fucntion(id){
return docuemnt.getElementById(id);
},
css: fucntion(id,key,value){
docuemnt.getElementById(id)[key] = value;
},
html: fucntion(id,html){
docuemnt.getElementById(id).innerHtml = html;
}
}

A.css('box','background','red');
// ...

2.适配器模式

将一个类的接口转化成另一个接口,以满足用户需求,使类之间接口的不兼容问题通过适配器得以解决。

1
2
// jQuery 适配器
window.A = A = jQuery;

参数适配器

1
2
3
4
5
6
7
8
9
10
11
12
13
function doSomeThing(obj){
var _adapter = {
name:'',
title:'',
age:'',
color:'',
size:100,
prize:50
}
for(var i in _adapter){
_adapter[i] = obj[i] || _adapter[i];
}
}

数据适配

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
var obj = {
name:'',
age:'',
job:''
}
function arrToObjAdapter(arr){
return {
name:arr[0],
age:arr[1],
job[2]
}
}
var test = arrToObjAdapter[obj];
console.log(test);

// 服务端数据适配
function ajaxAdapter(data){
return [data['key1'],data['key2'],data['key3']];
}
$.ajax....
{
doSomeThing(ajaxAdapter(res));
}

3.代理模式

由于一个对象不能直接引用另一个对象 ,所以需要通过代理对象 在这2个对象之间起到中介的作用。

跨域

1.同一域名不同的端口号 http://www.baidu.com:8081 http://www.baidu.com:8082

2.同一域名不同协议 http://www.baidu.com https://www.baidu.com

3.域名和域名对应的IP http://www.baidu.com http://10.10.10.10

4.主域和子域 http://www.baidu.com http://xx.baidu.com

5.子域和子域 http://tieba.baidu.com http://fanyi.baidu.com

script代理 和 JSONP

4.装饰者模式

在不改变原对象的基础上,通过对其进行包装拓展使原有对象可以满足用户的更复杂需求。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 装饰已有的功能对象
var decorator = function(input,fn){
// 获取事件源
var input = document.getElementById(input);
// 若事件源已经已经绑定事件
if(typeof input.onclick === 'function'){
// 缓存事件源原有回调函数
var oldClickFn = input.onclick;
// 为事件源定义新的事件
input.onclick = function(){
// 事件源原有回调函数
oldClickFn();
// 执行事件源新增回调函数
fn();
}
}else{
// 事件源未绑定事件,直接为事件源添加新增回调函数
input.onclick = fn;
}
}
// 为输入框装修
decorator('tel_input',function(){
document.getElementById('tel_demo_text').style.display = 'none';
})

5.桥接模式

在系统沿着多个维度变化的同时,又不增加其复杂度并已达到解耦。

实现层(元素绑定的事件)和抽象层(如修饰页面UI逻辑)解耦分离,使两部分可以独立变化。

  1. 提取共同点:相同逻辑代码提取处理
1
2
3
4
function changeColor(dom,color,bg){
dom.style.color = color;
dom.style.background = bg;
}
  1. 桥接:事件与业务 逻辑之间的桥梁:需要用一个方法将他们链接起来
1
2
3
4
5
6
spans[0].onmouseover = function(){
changeColor(this,'red','#ddd');
}
spans[0].onmouseout = function(){
changeColor(this,'#333','#f5f5f5');
}

6.组合模式

又称部份-整体模式,将对象组合成树形结构以表示部份整体的层次结构。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
// 每个成员要现有祖先 虚拟类
var News = function(){
this.children = []; //子类
this.element = null; //当前元素
}
News.prototype = {
init:funticon(){
throw new Error('请重写你的方法');
},
add:funticon(){
throw new Error('请重写你的方法');
},
getElement:funticon(){
throw new Error('请重写你的方法');
}
}

// 容器类构造函数
var Container = function(id,parent){
News.call(this); // 继承父类
this.id = id; // 模块ID
this.parent = parent; // 模块父容器
this.init(); // 构造方法
}

// 寄生式继承父类原型方法
inheritPrototype(Container,News);

//构建方法
Container.prototype.init = function(){
this.element = document.createElement('ul');
this.element.id = this.id;
this.element.className = 'new-container';
}
// 添加子元素
Container.prototype.add = function(child){
this.children.push(child);
this.element.appendChild(child.getElement());
return this;
}
// 获取当前元素
Container.prototype.getElement = function(){
return this.element;
}
// 显示方法
Container.prototype.show = function(){
this.parent.appendChild(this.element);
}

// 模块创建
var news1 = new Container('news',document.body);
news1.add(
//
).add(
//
)

7.享元模式

运用共享技术有效地支持大量的颗粒度的对象,避免对象间拥有相同内容造成多余的开销。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
var Flyweight = function(){
//已创建的元素
var created = [];
// 创建一个新闻包装容器
function create(){
var dom = document.createElement('div');
// 将容器插入新闻列表容器中
document.getElementById('container').appendChild(dom);
// 缓存新创建的元素
created.push(dom);
// 返回创建的新元素
return dom;
}
return {
// 获取创建新闻元素方法
getDiv: function(){
// 如果已创建的元素小于当前页元素总个数,则创建
if(created.length<5){
return create();
}else{
var div = created.shift();
created.push(div);
return div;
}
}
}
}

四、行为型设计模式

用于不同对象 之间职责划分或算法的抽像,不仅涉及类和对象,还涉及类或对象之间的交流模式并加以实现

1.模板方法模式

父类中定义一组操作算法骨架,而将一些实现步骤延迟到子类中,使得子类可以不改变父类的算法结构的同事可重新定义算法中某些实现步骤。(封装 弹出框方法 或提示框的思路)

2.观察者模式

又称作发布-订阅模式或消息机制,定义了一种依赖关系,解决主体对象 与观察者之间的功能耦合。

1
2
3
4
5
6
7
8
9
//将观察者放到闭包中,当页面加载就立即执行
var Observer = (function(){
var _message = {}; //防止消息队列暴露而篡改 因此设置私有变量
return {
regist:function(){},
fire:function(){},
remove:function(){},
}
})();

3.状态模式

当一个对象的内部状态发生改变时,会导致其行为的改变,这看起来像是改变了对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
//创建超级玛丽状态类
var MarryState = function(){
var _currentState = {}; //内部状态私有变量
var states = {
jump:function(){},
move:function(){},
shoot:function(){},
squat:function(){},
}
// 动作控制类
var Action = function(){
changeState:function(){
// 组合动作通过传递多个参数实现
var arg = arguments;
// 重置对内状态
_currentState = {};
如果有动作就添加动作
if(arg.length){
for(var i = 0;i<arg.length;i++){
_currentState[arg[i]] =true;
}
}
// 返回动作控制类
return this;
},
goes: function(){
// 触发一次动作
for(var i in currentState){
states[i] && states[i]();
}
return this;
}
}
// 返回接口方法
return {
change:Action.changeState,
goes:Action.goes
}
}


// 第一种使用
MarryState()
.change('jump','shoot')
.goes()
.goes()

// 第二种使用
var marry = new MarryState();
marry
.change('jump','shoot')
.goes()
.goes()

4.策略模式

将定义的一组算法封装起来,使其相互之间可以替换。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 价值策略对象
var priceStrategy = function(){
var stragtegy = {
return30 :function(price){}, // 100返30
return50 :function(price){}, // 100返50
percent90 :function(price){}, // 九折
}
return function(algorithm,price){
return stragtegy[algorithm] && stragtegy[algorithm](price)
}
}

var price = priceStrategy('return50','314');
console.log(price);

5.职责链模式

解决请求的发送者与请求的接受者之间的耦合,通过职责上的多个对象 对分解请求流程,实现请求在多个对象之间传递,直到最后一个对象完成请求的处理。

  1. 请求模块
  2. 响应数据适配模块
  3. 创建组件模块
  4. 单元测试

6.命令模式

将请求与实现解耦,并封装成独立对象,从而使不同的请求对客户端的实现参数化。

例如:将执行的命令封装,解决命令发起者与命令执行者之间的耦合。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
var canvasCMD = (function(){
var canvas = document.getElementById('canvas');
ctx = canvas.getContext('2d');
var Action = {
fillStyle : function(c){
ctx.fillStyle = c;
},
fillRect : function(x,y,width,height){
ctx.fillRect(x,y,width,height);
},
// ...
}
return {
// 命令接口
excute:function(msg){
if(!msg) return;
if(msg.length){
for(var i=0;i<msg.length;i++){
arguments.callee(msg[i]);
}
}else{
msg.param = Object.prototype.toString.call(msg.param) === '[Object Array]'?
msg.param : [msg.param];
Action[msg.command].apply(Action,msg.param);
}
}
}
})();

7.访问者模式

针对于对象结构中的元素,定义在不改变此对象的前提下访问结构中元素的新方法。

解决数据与数据的操作方法之间的耦合,将数据的操作方法独立于数据,使其可以自由变化。

1
2
3
4
5
6
7
8
// 访问器
var Visitor = (function(){
reutrn{
splice:function(){},
push:function(){},
pop:function(){},
}
})();

8.中介者模式

通过中介者对象封装一系列对象之间的交互,使对象之间不再相互引用,降低他们之间的耦合。

同观察者模式一样,中介者模式的主要业务也是通过模块间或者对象间的通信 ,来解决模块间或对象间的耦合。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 中介者对象
var Mediator = function(){
var _msg = {};
return {
// 订阅消息
register:function(type,action){
if(_msg[type]){
_msg[type].push(action);
}else{
_msg[type] = [];
_msg[type].push(action);
}
},
// 发送消息
send:function(type){
if(_msg[type]){
for(var i = 0;i<_msg[type].length;i++){
_msg[type][i] && _msg[type][i]();
}
}
}
}
}();

9.备忘录模式

在不破坏对象的封装性的前提下,在对象之外铺货并保存该对象内部的状态以便日后对象使用或者对象恢复到以前的某个状态。

主要针对现有的数据或状态做为缓存,为将来某个时刻使用或恢复做准备。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 缓存数据 分页点击下一页的数据 又返回上一页 数据可以缓存
var Paget = function{
var cache = {};
return function(page,fn){
if(cache[page]){
showPage(page,cache[page]);
fn && fn();
}else{
$.post((),{

showPage(page,res.data);
cache[page] = res.data;
fn && fn();

})
}
}
}();

10.迭代器模式

在不暴露对象 内部结构的同时,可以顺序地访问聚合对象内部的元素。

优化循环语句的一种可行方案,它使得程序清晰易读。可以顺序的访问一个聚合对象中的每一个元素。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 迭代器
var Iterator = function(items,container){
var container = container && document.getElementById(container) || document,
items = container.getElementByTagName(items),
length = item.length,
index = 0;
var splice = [].splice;
return {
first : function(){},
second : function(){},
pre : function(){},
next : function(){},
get : function(){},
dealEach : function(){},
dealItem : function(){},
exclusive : function(){},
}
}

11.解释器模式

对于一种语言,给出其文法表示形式,并定义一种解释器,通过使用这种解释器来解释语言中定义的句子。

对客户提出的需求,经过解析而形成的一个抽象解释程序。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// xPath解释器
var Interpreter = (function(){
function getSublingName(node){}
return function(node,wrap){
var path = [];
var wrap = wrap || document;
if(node===wrap){
if(wrap.nodeType == 1){
path.push(wrap.nodeName.toUpperCase());
return path;
}
}
return path;
}
})();

五、技巧型设计模式

通过一些特定技巧来解决组件的某些方面的总理,这些技巧一般通过实践经验总结得到。

1.链模式

通过在对象方法中将当前对象返回,实现对同一个对象多个方法的链式调用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
var A = function(selector){
return new A.fn.init(selector);
}

A.fn = A.prototype = {
constructor:A,
init:function(selector){
//
}
}
A.fn.init.prototype = A.fn;
// 添加方法
A.fn.extend({
on:(function(){
//...
})()
})
A.fn.extend({
css:(function(){
//...
})()
})

A('div')
.css({
//...
})
.on('click',function(){
//...
})

2.委托模式

多个对象 接收 并处理同一个请求,他们将请求委托给另一个对象 统一处理请求。

通过委托者将请求给被委托者去处理实现,解决了请求与委托者之间的耦合。

还能解决内存泄露(IE旧浏览器)

1
2
3
4
5
6
7
8
9
$.get("./deal.php?g=banner",function(res){
//
})
$.get("./deal.php?g=news",function(res){
//
})
$.get("./deal.php?g=member",function(res){
//
})

数据分发

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var Deal ={
banner:function(){
//
},
news:function(){
//
},
member:function(){
//
}
}
$.get('./deal.php?',fucntion(res){
for(var i in res){
Deal[i] && Deal[i](res[i])
}
})

3.数据访问对象模式

抽象和封装数据源的访问与存储,DAO通过对数据源链接的管理方便对数据的访问与存储。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
/*本地存储类*/
var BaseLocalStorage = function(preId,timeSign){
this.preId = preId;
this.timeSign = timeSign || '|-|';
}

BaseLocalStorage.protorype = {
// 操作状态
status:{
SUCCESS : 0,
FAILURE : 1,
OVERFLOW : 2,
TIMEOUT : 3
},
// 保存本地存储链接
storage: localStorage || window.localStorage,
// 获取本地存储数据库数据真实字段
getKey: function(key){
return this.preId + key;
},
// 添加数据
set: function(key,value,callback,time){

},
// 获取数据
get: function(key,callback){

},
// 删除数据
remove: function(key,callback){

}
}

4.节流模式

对重复的业务逻辑进行节流控制,执行最后一次操作并取消其它操作,以提高性能。

  1. 清除将要执行的函数,传递两个参数(是否清除,执行函数)。如果true,则表示清除将要执行的函数,同时会判断第二个参数有没有计时器句柄,有则清除计时器。
  2. 延迟执行函数(执行函数,相关参数)。在节流器内部首先要为执行函数绑定一个计时器句柄,来保存该执行函数的计时器;相关参数包括执行函数在执行时的作用域,执行函数的参数,执行函数延迟执行的时间。
  3. 适用于:返回顶部、浮层、图片延迟加载….

5.简单模板模式

通过格式化字符串拼凑出视图避免创建视图时大量字点操作。优化内存开销。

DOM操作创建视图造成大量消耗。正则方式去格式化字符串更好。

目前已经有成熟的模板第三方,当然底层的模板生成器原理也是非常重要的知识。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
A.view = function(name){
var v = {
code: '<pre><code> {#code#} </code></pre>',
img: '<img src="{#src#}" alt="{#alt#}" title="{#title#}">',
part: '<div id="{#id#}">{#part#}</div>'
}
if(Object.prototype.toString.call(name)==="[object Array]"){
var tpl = '';
for(var i=0,len=name.length;i<len;i++){
tpl += arguments.callee(name[i]);
}
return tpl;
}else{
return v[name] ? v[name] : ('<'+name+'>{#'+name+'#}</'+name+'>');
}
}

6.惰性模式

减少每次代码执行时的重复性分支判断,通过对对象重定义来屏蔽原对象中的分支判断。

这是一种拖延模式,由于对象的创建或者数据的计算会花费高昂的代价,因此页面之处会延迟对这一类对象的创建。

  1. 文件加载后立即执行对象方法来冲定义对象
  2. 当第一次使用对象时重新定义对象。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// 加载即执行
A.on = function(dom,type,fn){
if(document.addEventListener){
return function(dom,type,fn){
dom.addEventListener(type,fn,false);
}
} else if(document.attachEvent){
return function(dom,type,fn){
dom.attachEvent('on'+type,fn);
}
} else {
return function(dom,type,fn){
dom('on'+type) = fn;
}
}
}();

// 惰性执行
A.on = function(dom,type,fn){
if(document.addEventListener){
A.on = function(dom,type,fn)
dom.addEventListener(type,fn,false);
}
} else if(document.attachEvent){
A.on = function(dom,type,fn)
dom.attachEvent('on'+type,fn);
}
} else {
A.on = function(dom,type,fn)
dom('on'+type) = fn;
}
}

// 执行重新定义on方法
A.on(dom,type,fn);
}

7.参与者模式

在特定的作用域中执行给定的函数,并将参数原封不动地传递。

重点:函数绑定和函数柯理化

后期重点学习

8.等待着模式

通过对多个异步进程的监控,来触发未来发生的动作。

主要处理耗时比较长的操作。提供回调方案。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
// 等待者对象 
var Waiter = function(){
// 注册等待对象容器
var dfd = [],
doneArr = [],
failArr = [],
slice = Array.prototype.sclice,
that = this;
// 监控对象类
var Primise = function(){
this.resolved = false;
this.rejected = false;
}
// 监控对象原型方法
Primise.prototype = {
resolve: function(){i
this.resolved = true;
if(!dfd.length) return;
// 遍历所有注册了的监控对象
for(var i =dfd.length-1;i>=0;i--){
if(dfd[i]&&!dfd[i].resolved || dfd[i].rejected){
return;
}
}
dfd.slice(i,1);//清除监控对象
_exec(doneArr);
},
reject: function(){
this.rejected = true;
if(!dfd.length) return;
dfd.slice(0); //清除所有监控对象
_exec(failArr);

}
}
// 创建监控对象
that.Deferred = function(){
return new Promise();
}
// 回调执行方法
function _exec(arr){
var i = 0,len = arr.length;
for(;i<len;i++){
try{
arr[i] && arr[i]();
}catch(e){}
}
}

// 监控异步方法 参数 :监控对象
that.when = function(){
dfd = slice.call(arguments); // 设置监控对象
var i = dfd.length;
for(--i,i>=0;i--){
// 如果不存在监控对象,监控对象已经解决,不是监控对象
if(!dfd[i] || dfd[i].resolved || dfd[i].rejected || !dfd[i] instanceof Primise){
dfd.slice(i,1); //清理内存 清理当前监控对象
}
}
// 返回等待者对象
return that;
};
// 解决成功回调函数添加方法
that.done = function(){
doneArr = doneArr.concat(slice.call(arguments));
return that;
};
// 解决失败回调函数添加方法
that.fail = function(){
failArr = failArr.concat(slice.call(arguments));
return that;
};
}

// 监控对象

六、架构型设计模式

是一类框架 结构,通过提供一些子系统,指定他们的职责,并将他们条理清楚地组织在一起。

已经有非常成熟的框架,只作简要概述,底层原理查看相关页码。

1.同步模块模式

模块化:将复杂的系统分解成高内聚、低耦合的模块 ,使系统开发变得可控、可维护、可拓展,提高模块 的复用率。

同步模块模式:SMD 请求发出后,无论模块是否存在,立即执行后续的逻辑,实现模块开发中对模块的立即引用。分而治之。

底层原理:P255

2.异步模块模式

异步模块模式:AMD请求发出后,继续其他业务 逻辑,知道模块加载完成执行后续逻辑,实现模块开发中对模块加载完成后的引用。

底层原理:P255

3.Widget模式

将页面分解成部件,针对部件开发,最终组合成完整的页面。

1
2
3
4
5
6
7
8
// 模板引擎
F.moudule('lib/template',function(){
var _TplEngine = function(){},
_getTpl = function(){},
_dealTpl = function(){},
_compileTpl = function(){}
return _TplEngine;
})

4.MVC模式

model view controller 将业务逻辑、数据、视图分离的方式组织架构代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
var MVC = MVC || {};

MVC.model = function(){
var M = {};
M.data = {};
M.conf = {};
return {
getData:function(m){//获取服务端数据
return M.data[m];
},
getConf:function(c){// 获取配置数据
return M.conf[c];
},
setData:function(m,v){//设置服务端数据
M.data[m] = v;
return this;
},
setConf:function(c){//设置配置数据
M.data[c] = v;
return this;
},
}
}();

MVC.view = function(){
var M = MVC.model;
var V = {};
return function(v){
V[v];
}
}();

MVC.controller = function(){
var M = MVC.model;
var V = MVC.view;
var C = {};
}();

5.MVP模式

模型 视图 管理器Presenter。View不直接引用Model的数据,而是通过presenter实现对model层的数据访问。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
~(function(window){
var MVP = function(){};
MVP.model = function(){};
MVP.view = function(){};
MVP.presenter = function(){
var V = MVP.view;
var M = MVP.model;
var C = {};
return {
init: function(){
for(var i in C){
C[i] && C[i][M,V,i];
}
}
}

};
// 入口
MVP.init = function(){};
// 向外暴露
window.MVP = MVP;
})(window)

6.MVVM模式

模型 - 视图 - 视图模型 (VM)

底层原理:P298