《JavaScript 模式》作者: Stoyan Stefanov 译: 陈新
养分
1. 自调用构造函数: 实现不使用new
关键字,构造出实例。
1 | function Waffle() { |
2. 备忘模式:
1 | var myFunc = function() { |
3. 配置对象模式: 将参数列表封装到一个对象内。
1 | function addPerson(first, last, dob, gender, address) {...} |
4. 通用命名空间函数: 减少全局变量,避免命名冲突。
1 | var MYAPP = MYAPP || {}; |
5. 模块模式: 提供了结构化的思想并且有助于组织日益增长的代码。可以根据所编写的软件的需求(千变万化的需求)添加、替换或删除这些模块。
1 | MYAPP.namespace("MYAPP.utilities.array").utilities.array = (function() { |
6. 创建构造函数的模块: 使用模块模式返回一个构造函数。
1 | MYAPP.namespace("MYAPP.utilities.Array").utilities.Array = (function() { |
7. 将全局变量导入到模块中: 有助于加速即时函数中的全局符号解析的速度,因为这些导入的变量成为了该函数的局部变量。
1 | MYAPP.utilities.module = (function(app, global) { |
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
76
77
78
79
80
81
82
83
84
85
86
87
88
89// Sandbox 构造函数
function Sandbox() {
// 将参数转换成一个数组
var args = Array.prototype.slice.call(arguments),
// 最后一个参数是回调函数
callback = args.pop(),
// 模块可以作为一个数组传递,或作为单独的参数传递
modules = (args[0] && typeof args[0] === "string") ? args : args[0],
i;
// 确保该函数作为构造函数被调用
if (!(this instanceof Sandbox)) {
return new Sandbox(modules, callback);
}
// 需要向 `this` 添加的属性
this.a = 1;
this.b = 2;
// 现在向该核心 `this` 对象添加模块
// 不指定模块名称或指定“*”都表示“使用所有模块”
if (!modules || modules === "*") {
modules = [];
for (i in Sandbox.modules) {
if (Sandbox.modules.hasOwnProperty(i)) {
modules.push(i);
}
}
}
// 初始化所需的模块
for (i = 0; i < modules.length; i += 1) {
Sandbox.modules[modules[i]](this);
}
callback(this);
}
Sandbox.prototype = {
name : "My Application",
version : "1.0",
getName : function() {
return this.name;
}
};
Sandbox.prototype.constructor = Sandbox;
// 增加模块
Sandbox.modules = {};
Sandbox.modules.dom = function(box) {
box.getElement = function() {};
box.getStyle = function() {};
box.foo = "bar";
};
Sandbox.modules.event = function(box) {
// 如果需要, 就访问 Sandbox 原型,如:
// box.constructor.prototype.m = "mmm";
box.attachEvent = function() {};
box.dettachEvent = function() {};
};
Sandbox.modules.ajax = function(box) {
box.makeRequest = function() {};
box.makeResponse = function() {};
};
// usage
// 使用 ajax 和 event 模块
Sandbox(["ajax", "event"], function(box) {
//console.log(box);
});
// 使用所有可用模块
Sandbox("*", function(box) {
});
Sandbox(function(box) {
});
// 模块嵌套
Sandbox("dom", "event", function(box) {
Sandbox("ajax", function(box) {
});
});
9. 圣杯继承模式1
2
3
4
5
6
7
8
9var inherit = (function() {
var F = function() {};
return function(C, P) {
F.prototype = P.prototype;
C.prototype = new F();
C.uber = P.prototype;
C.prototype.constructor = C;
}
});
10. 浅拷贝对象1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17function extend(parent, child) {
var i;
child = child || {};
for (i in parent) {
if (parent.hasOwnProperty(i)) {
child[i] = parent[i];
}
}
return child;
}
// usage
var dad = {name: "Adam"};
var kid = extend(dad);
console.log(kid.name); // "Adam"
11. 深拷贝对象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
32function extendDeep(parent, child) {
var i,
toStr = Object.prototype.toString,
astr = "[object Array]";
child = child || {};
for (i in parent) {
if (parent.hasOwnProperty(i)) {
if (typeof parent[i] === "object") {
child[i] = (toStr.call(parent[i]) === astr) ? [] : {};
extendDeep(parent[i], child[i]);
} else {
child[i] = parent[i];
}
}
}
return child;
}
// usage
var dad = {
counts: [1, 2, 3],
reads: {paper: true}
};
var kid = extendDeep(dad);
kid.counts.push(4);
console.log(kid.counts.toString()); // "1,2,3,4"
console.log(dad.counts.toString()); // "1,2,3"
console.log(dad.reads === kid.reads); // false
12. 混入模式(mix-in),就是将多个对象组合成一个新的对象。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21function mix() {
var arg,
prop,
child = {};
for (arg = 0; arg < arguments.length; arg += 1) {
for (prop in arguments[arg]) {
if (arguments[arg].hasOwnProperty(prop)) {
child[prop] = arguments[arg][prop];
}
}
}
return child;
}
// usage
var cake = mix({
{eggs: 2, large: true},
{butter: 1, salted: true}
});
13. 单例模式(Singleton),保证一个特定类仅有一个实例。当第二次使用这个特定类创建对象的时候,应该得到与第一次所创建对象完全相同。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16function Universe() {
var instance;
Universe = function Universe() {
return instance;
}
Universe.prototype = this;
instance = new Universe();
instance.constructor = Universe;
instance.start_time = 0;
instance.bang = "Big";
return instance;
}
14. 迭代器模式(Iterator),提供一个简单的接口,顺序遍历数据集合中的各个元素。
1 | var agg = (function () { |
15. 装饰者模式,可以在运行时动态添加附加功能到对象中。装饰者模式的一个比较方便的特征在于其预期行为的可定制和可配置特性。可以从仅具有一些基本功能的普通对象开始,然后从可用装饰资源池中选择需要用于增强普通对象的那些功能,并且按照顺序进行装饰,尤其是当装饰顺序很重要的时候。我感觉就是一个普通的材料通过了流水线的加工后产生了一个新的产品。也可说是一个对象进行了升级的过程,改变了自己的功能。
- 方法一: 让每个装饰者成为一个对象,并且该对象包含了应该被重载的方法。每个装饰者实际上继承了目前已经被前一个装饰者进行增强后的对象。每个装饰方法在 uber (被继承的对象) 上调用了同样的方法并获取其值,此外它还继续执行了一些其它操作。
1 | function Sale(price) { |
- 方法二: 使用列表实现,将装饰者放在一个列表中,可以很容易的支持反装饰或撤销装饰(就是对装饰者列表进行 push 和 pop 的过程)。
1 | function Sale(price) { |
16. 策略模式,策略模式定义了算法家族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化不会影响到使用算法的客户。就是先抽象出相同的处理流程(算法调用的过程,或做的事情),然后根据在流程中获取到的算法策略不同,从而使流程内具体要做的事就不同。感觉像是框架(流程),数据(需要处理的数据),算法(算法策略)
模式。
1 | var validator = { |
使用: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// usage
// 定义types里存放的各种验证类
// 验证给定的值是否不为空
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: "传入的值只能保护字母和数字,不能包含特殊字符"
};
// 定义需要验证的数据集合,然后还需要定义每种数据需要验证的规则类型
var data = {
first_name: "Tom",
last_name: "Xu",
age: "unknown",
username: "TomXu"
};
validator.config = {
first_name: 'isNonEmpty',
age: 'isNumber',
username: 'isAlphaNum'
};
validator.validate(data);
if (validator.hasErrors()) {
console.log(validator.messages.join("\n"));
}
17. 外观模式,为子系统的一组接口
提供一个一致的界面(接口),此模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。感觉就是对一些接口的组合(封装),形成一个高层接口(抽象接口),以备外界调用。
1 | var myEvent = { |