单例模式
保证一个类只有一个实例,提供一个唯一的访问点来暴露该对象。
1 2 3 4 5 6 7
| var mySingleton = { property1: "something", property2: "something else", method1: function () { console.log('hello world'); } };
|
构造函数模式
在js中没有类的概念,但是有特殊的构造函数,通过new关键字来调用定义的函数,在构造函数内部通过this引用属性方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| function Car(model, year, miles) { this.model = model; this.year = year; this.miles = miles; this.output= function () { return this.model + "走了" + this.miles + "公里"; }; }
var tom= new Car("大叔", 2009, 20000); var dudu= new Car("Dudu", 2010, 5000);
console.log(tom.output()); console.log(dudu.output());
|
建造者模式
将一个复杂对象的构建与其表示相分离,提供一种“封装机制”来区分出对象中复杂部分的变换。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| function getBeerById(id, callback) { // 使用ID来请求数据,然后返回数据. asyncRequest('GET', 'beer.uri?id=' + id, function (resp) { // callback调用 response callback(resp.responseText); }); }
var el = document.querySelector('#test'); el.addEventListener('click', getBeerByIdBridge, false);
function getBeerByIdBridge(e) { getBeerById(this.id, function (beer) { console.log('Requested Beer: ' + beer); }); }
|
仔细观察也就是我们经常使用的互相调用。
工厂模式
工厂一般用于定义对象的接口,而接口一般由子类决定实例化。
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 page = page || {}; page.dom = page.dom || {}; //子函数1:处理文本 page.dom.Text = function () { this.insert = function (where) { var txt = document.createTextNode(this.url); where.appendChild(txt); }; };
//子函数2:处理链接 page.dom.Link = function () { this.insert = function (where) { var link = document.createElement('a'); link.href = this.url; link.appendChild(document.createTextNode(this.url)); where.appendChild(link); }; };
//子函数3:处理图片 page.dom.Image = function () { this.insert = function (where) { var im = document.createElement('img'); im.src = this.url; where.appendChild(im); }; };
|
装饰者模式
旨创建一个需要被装饰的类,通过在子类中添加不同的行为进而达到实现影响原有类实例的模式,其实是一种实现继承的变体。
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
| //需要装饰的类(函数) function Macbook() { this.cost = function () { return 1000; }; }
function Memory(macbook) { this.cost = function () { return macbook.cost() + 75; }; }
function BlurayDrive(macbook) { this.cost = function () { return macbook.cost() + 300; }; }
function Insurance(macbook) { this.cost = function () { return macbook.cost() + 250; }; }
// 用法 var myMacbook = new Insurance(new BlurayDrive(new Memory(new Macbook()))); console.log(myMacbook.cost());
|
外观模式
为子系统中的一组接口提供了一个一致的界面,简化类中的接口。
(一个接口中包含了需要调用的业务接口)。
1 2 3 4 5 6 7 8
| var mobileEvent = { // ... stop: function (e) { e.preventDefault(); e.stopPropagation(); } // ... };
|
代理模式
顾名思义,需要有一份中间人去转办当事人之间的业务职能。
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 girl = function (name) { this.name = name; };
// 这是dudu var dudu = function (girl) { this.girl = girl; this.sendGift = function (gift) { alert("Hi " + girl.name + ", dudu送你一个礼物:" + gift); } };
// 大叔是代理 var proxyTom = function (girl) { this.girl = girl; this.sendGift = function (gift) { (new dudu(girl)).sendGift(gift); // 替dudu送花咯 } };
// 调用 var proxy = new proxyTom(new girl("酸奶小妹")); proxy.sendGift("999朵玫瑰");
|
观察者模式
也称发布/订阅模式,为当代MVVM框架中最为广泛传播的设计模式,它定义了一种一对多的关系,当系统有状态更改时,使得它们能够自动更新自身。
- 支持简单的广播通信,自动通知所有已经订阅过的对象。
- 页面载入后目标对象很容易与观察者存在一种动态关联,增加了灵活性。[双绑机制]
- 目标对象与观察者之间的抽象耦合关系能够单独扩展以及重用。
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
| var pubsub = {}; (function (q) {
var topics = {}, // 回调函数存放的数组 subUid = -1; // 发布方法 q.publish = function (topic, args) {
if (!topics[topic]) { return false; }
setTimeout(function () { var subscribers = topics[topic], len = subscribers ? subscribers.length : 0;
while (len--) { subscribers[len].func(topic, args); } }, 0);
return true;
}; //订阅方法 q.subscribe = function (topic, func) {
if (!topics[topic]) { topics[topic] = []; }
var token = (++subUid).toString(); topics[topic].push({ token: token, func: func }); return token; }; //退订方法 q.unsubscribe = function (token) { for (var m in topics) { if (topics[m]) { for (var i = 0, j = topics[m].length; i < j; i++) { if (topics[m][i].token === token) { topics[m].splice(i, 1); return token; } } } } return false; }; } (pubsub));
// 进行订阅与发布 //来,订阅一个 pubsub.subscribe('example1', function (topics, data) { console.log(topics + ": " + data); });
//发布通知 pubsub.publish('example1', 'hello world!'); pubsub.publish('example1', ['test', 'a', 'b', 'c']); pubsub.publish('example1', [{ 'color': 'blue' }, { 'text': 'hello'}]);
|
或者是通过原型来创建。
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
| function Observer() { this.fns = []; } Observer.prototype = { subscribe: function (fn) { this.fns.push(fn); }, unsubscribe: function (fn) { this.fns = this.fns.filter( function (el) { if (el !== fn) { return el; } } ); }, update: function (o, thisObj) { var scope = thisObj || window; this.fns.forEach( function (el) { el.call(scope, o); } ); } };
//测试 var o = new Observer; var f1 = function (data) { console.log('Robbin: ' + data + ', 赶紧干活了!'); };
var f2 = function (data) { console.log('Randall: ' + data + ', 找他加点工资去!'); };
o.subscribe(f1); o.subscribe(f2);
o.update("Tom回来了!")
//退订f1 o.unsubscribe(f1); //再来验证 o.update("Tom回来了!");
|
策略模式
定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换。
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 validator = {
// 所有可以的验证规则处理类存放的地方,后面会单独定义 types: {},
// 验证类型所对应的错误消息 messages: [],
// 当然需要使用的验证类型 config: {}, }
// 验证给定的值是否不为空 validator.types.isNonEmpty = { validate: function (value) { return value !== ""; }, instructions: "传入的值不能为空" };
// 验证给定的值是否是数字 validator.types.isNumber = { validate: function (value) { return !isNaN(value); }, instructions: "传入的值只能是合法的数字,例如:1, 3.14 or 2010" };
// 验证给定的值是否只是字母或数字 validator.types.isAlphaNum = { validate: function (value) { return !/[^a-z0-9]/i.test(value); }, instructions: "传入的值只能保护字母和数字,不能包含特殊字符" };
|
类似不同的验证目的通过不同的验证算法实现。
迭代器模式
提供一种方法顺序一个聚合对象中各个元素,而又不暴露该对象内部表示。
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 agg = (function () { var index = 0, data = [1, 2, 3, 4, 5], length = data.length;
return { next: function () { var element; if (!this.hasNext()) { return null; } element = data[index]; index = index + 2; return element; },
hasNext: function () { return index < length; },
rewind: function () { index = 0; },
current: function () { return data[index]; }
}; } ());
|
就到这里吧!