├── chapter1
├── README.md
├── 1.js
├── 2.js
├── 3.js
├── 4.js
├── 6.js
└── 5.js
├── chapter6
├── README.md
└── 1.js
├── chapter4
├── README.md
└── 1.js
├── chapter5
├── README.md
└── 1.js
├── chapter35
├── README.md
└── 1.js
├── chapter7
├── README.md
├── 2.js
└── 1.js
├── chapter26
├── README.md
└── 1.js
├── chapter3
├── README.md
├── 2.js
└── 1.js
├── chapter31
├── README.md
├── 1.js
└── 2.js
├── chapter36
├── test
│ ├── test.js
│ ├── test2.js
│ └── index.html
├── README.md
└── 1.js
├── chapter38
├── README.md
└── 1.js
├── chapter29
├── README.md
└── 1.js
├── chapter34
├── README.md
└── 1.js
├── chapter13
├── README.md
├── 2.js
└── 1.js
├── chapter24
├── README.md
├── 1.js
└── 2.js
├── chapter27
├── README.md
└── 1.js
├── chapter18
├── README.md
├── 1.js
└── 2.js
├── chapter14
├── README.md
└── 1.js
├── chapter30
└── README.md
├── chapter16
├── README.md
├── 2.js
└── 1.js
├── chapter37
├── README.md
└── 1.js
├── chapter9
├── README.md
└── 1.js
├── chapter8
├── README.md
├── 2.js
├── 1.js
└── 3.js
├── chapter39
├── README.md
└── 1.js
├── chapter32
├── README.md
├── 1.js
└── 2.js
├── chapter15
├── README.md
└── 1.js
├── chapter28
├── README.md
├── 2.js
├── 1.js
├── 3.js
└── 4.js
├── chapter10
├── README.md
├── 3.js
├── 2.js
└── 1.js
├── chapter2
├── README.md
├── 2.js
├── 5.js
├── 4.js
├── 1.js
├── 3.js
└── 6.js
├── chapter25
├── README.md
├── 2.js
├── 3.js
├── 4.js
└── 1.js
├── chapter33
├── README.md
├── 3.js
├── 1.js
├── 4.js
├── 5.js
└── 2.js
├── chapter17
├── README.md
├── 1.js
├── 3.js
└── 2.js
├── chapter22
├── README.md
├── 1.js
└── 2.js
├── chapter20
├── README.md
└── 1.js
├── chapter12
├── README.md
└── 1.js
├── chapter23
├── README.md
├── 1.js
└── 2.js
├── chapter21
├── README.md
└── 1.js
├── chapter19
├── 2.js
├── README.md
└── 1.js
├── LICENSE
└── README.md
/chapter1/README.md:
--------------------------------------------------------------------------------
1 | # 第一章
2 |
3 | 灵活的语言————javascript
--------------------------------------------------------------------------------
/chapter6/README.md:
--------------------------------------------------------------------------------
1 | # 第六章
2 |
3 | 建造者模式
4 |
5 | * 1.js - 建造者模式
--------------------------------------------------------------------------------
/chapter4/README.md:
--------------------------------------------------------------------------------
1 | # 第四章
2 |
3 | 工厂方法模式
4 |
5 | * 1.js - 工厂方法模式
--------------------------------------------------------------------------------
/chapter5/README.md:
--------------------------------------------------------------------------------
1 | # 第五章
2 |
3 | 抽象工厂模式
4 |
5 | * 1.js - 抽象工厂模式
--------------------------------------------------------------------------------
/chapter35/README.md:
--------------------------------------------------------------------------------
1 | # 第三十五章
2 |
3 | 同步模块模式(waiter)
4 |
5 | * 1.js - 同步模块模式
--------------------------------------------------------------------------------
/chapter7/README.md:
--------------------------------------------------------------------------------
1 | # 第七章
2 |
3 | 原型模式
4 |
5 | * 1.js - 原型模式
6 | * 2.js - 原型继承
--------------------------------------------------------------------------------
/chapter26/README.md:
--------------------------------------------------------------------------------
1 | # 第二十六章
2 |
3 | 解释器模式(Interpreter)
4 |
5 | * 1.js - 解释器模式
6 |
--------------------------------------------------------------------------------
/chapter3/README.md:
--------------------------------------------------------------------------------
1 | # 第三章
2 |
3 | 简单工厂模式
4 |
5 | * 1.js - 简单工厂模式
6 | * 2.js - 简单工厂模式2
--------------------------------------------------------------------------------
/chapter31/README.md:
--------------------------------------------------------------------------------
1 | # 第三十一章
2 |
3 | 简单模板模式
4 |
5 | * 1.js - 模板模式
6 | * 2.js - 模板模式2
--------------------------------------------------------------------------------
/chapter36/test/test.js:
--------------------------------------------------------------------------------
1 | F.module('test', function () {
2 | return {
3 | a: '123'
4 | }
5 | });
--------------------------------------------------------------------------------
/chapter36/test/test2.js:
--------------------------------------------------------------------------------
1 | F.module('test2', function () {
2 | return {
3 | a: '456'
4 | }
5 | });
--------------------------------------------------------------------------------
/chapter36/README.md:
--------------------------------------------------------------------------------
1 | # 第三十六章
2 |
3 | 异步模块模式(AMD - Asynchronous Module Definition)
4 |
5 | * 1.js - 异步模块模式
--------------------------------------------------------------------------------
/chapter38/README.md:
--------------------------------------------------------------------------------
1 | # 第三十八章
2 |
3 | MVC模式:model(模型) - view(视图) - controller(控制器)
4 |
5 | * 1.js - MVC模式
--------------------------------------------------------------------------------
/chapter29/README.md:
--------------------------------------------------------------------------------
1 | # 第二十九章
2 |
3 | 数据访问对象模式
4 |
5 | * 1.js - localStorage封装
6 |
7 | 这不是设计模式,只是一个对localstorage的一个封装
--------------------------------------------------------------------------------
/chapter34/README.md:
--------------------------------------------------------------------------------
1 | # 第三十四章
2 |
3 | 等待者模式(waiter)
4 |
5 | 通过对多个异步进程监听,来触发未来发生的动作
6 |
7 | * 1.js - 等待者模式(模拟一个简单的promise)
--------------------------------------------------------------------------------
/chapter13/README.md:
--------------------------------------------------------------------------------
1 | # 第十三章
2 |
3 | 桥接模式(Bridge)
4 |
5 | 在系统沿着多个维度变化的同时,又不增加其复杂度并已达到解耦
6 |
7 | * 1.js - 桥接模式(简单)
8 | * 2.js - 桥接模式
--------------------------------------------------------------------------------
/chapter24/README.md:
--------------------------------------------------------------------------------
1 | # 第二十四章
2 |
3 | 备忘录模式(Memento)
4 |
5 | 我的理解,其实就是一个普通的缓存机制。。
6 |
7 | * 1.js - 备忘录模式
8 | * 2.js - 我自己写的缓存工具函数
--------------------------------------------------------------------------------
/chapter27/README.md:
--------------------------------------------------------------------------------
1 | # 第二十七章
2 |
3 | 链模式(Operate of Responsibility)
4 |
5 | 通过在对象方法中将当前对象返回,实现对同一个对象多个方法的链式调用。
6 |
7 | * 1.js - 链模式
8 |
--------------------------------------------------------------------------------
/chapter18/README.md:
--------------------------------------------------------------------------------
1 | # 第十八章
2 |
3 | 状态模式(State):当一个对象的内部状态发生改变时,会导致其行为的改变,这看起来像是改变了对象。
4 |
5 | * 1.js - bad 不好的案例
6 | * 2.js - bood 使用状态模式之后
--------------------------------------------------------------------------------
/chapter14/README.md:
--------------------------------------------------------------------------------
1 | # 第十四章
2 |
3 | 组合模式(Composite)
4 |
5 | 又称部分-整体模式,将对象整合成树形结构以表示“部分整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性
6 |
7 | * 1.js - 组合模式
--------------------------------------------------------------------------------
/chapter30/README.md:
--------------------------------------------------------------------------------
1 | # 第三十章
2 |
3 | 节流模式
4 |
5 | 本章不属于设计模式的范畴,所以不写例子了,本章主要讲了几个方面
6 |
7 | * 返回顶部抖动问题
8 | * 鼠标移出延迟隐藏浮动层
9 | * 图片延迟加载
10 | * 统计打包
--------------------------------------------------------------------------------
/chapter16/README.md:
--------------------------------------------------------------------------------
1 | # 第十六章
2 |
3 | 模板方法(TemplateMethod)父类中定义一组操作算法骨架,而将一些实现步骤延迟到子类中,使得子类可以不改变一个算法的结构即可重定义该算法的某些实现步骤。
4 |
5 | * 1.js - 模板方法模式
6 | * 2.js - 模板方法模式2
--------------------------------------------------------------------------------
/chapter37/README.md:
--------------------------------------------------------------------------------
1 | # 第三十七章
2 |
3 | Widget模式:Widget模式是指借用 Web Widget 思想将页面分解成组件,针对部件开发,最终整合成完整的页面。
4 |
5 | PS:这章其实是演示了一下如何实现一个模板引擎。。。。
6 |
7 | * 1.js - 模板引擎模块
--------------------------------------------------------------------------------
/chapter9/README.md:
--------------------------------------------------------------------------------
1 | # 第九章
2 |
3 | 外观模式
4 |
5 | 为一组复杂的子系统接口提供一个更高级的统一接口,通过这个接口使得对子系统接口的访问更容易。
6 |
7 | 在javascript中有时也会用于底层结构兼容性做统一封装来简化用户使用
8 |
9 | * 1.js - 外观模式
--------------------------------------------------------------------------------
/chapter8/README.md:
--------------------------------------------------------------------------------
1 | # 第八章
2 |
3 | 单例模式
4 |
5 | * 1.js - 单例模式(创建命名空间)
6 | * 2.js - 静态变量(无法修改的静态变量)
7 | * 3.js - 惰性单例(有时候对于单例对象需要延迟创建,所以在单例中还存在一种延迟创建的形式,有人也称之为‘惰性创建’)
--------------------------------------------------------------------------------
/chapter39/README.md:
--------------------------------------------------------------------------------
1 | # 第三十九章
2 |
3 | MVP模式:model(模型) - view(视图) - Presenter(管理器),view层不能直接引用model层内的数据,二是通过presenter层实现对model层内的数据访问,即所有层次的交互都发生在presenter层中
4 |
5 | * 1.js - MVP模式
--------------------------------------------------------------------------------
/chapter32/README.md:
--------------------------------------------------------------------------------
1 | # 第三十二章
2 |
3 | 惰性模式(layier)
4 |
5 | 减少每次代码执行时的重复性的分支判断,通过对对象重新定义来屏蔽原对象中的分支判断
6 |
7 | * 1.js - 惰性模式(加载时执行)
8 | * 2.js - 惰性模式(调用时执行)
9 |
10 | 个人觉得这章的内容还是挺有用的
--------------------------------------------------------------------------------
/chapter15/README.md:
--------------------------------------------------------------------------------
1 | # 第十五章
2 |
3 | 享元模式(Flyweight),运行共享技术有效地支持大量细粒度的对象,避免对象拥有相同内容造成多余的开销,使大家共享一个类(元类)。
4 |
5 | * 1.js - 享元模式
6 |
7 | 根据我自己对享元模式的理解,享元模式的精髓就在于『创建对象的同时,缓存一份对象,日后直接对缓存的对象做操作』
--------------------------------------------------------------------------------
/chapter28/README.md:
--------------------------------------------------------------------------------
1 | # 第二十八章
2 |
3 | 委托模式
4 |
5 | 其实就是事件委托
6 |
7 | * 1.js - 事件委托
8 | * 2.js - 事件委托2(通过事件委托为 当前页面不存在的元素 绑定事件)
9 | * 3.js - 事件委托3(解决内存泄露)
10 | * 4.js - 事件委托4(数据分发)
11 |
--------------------------------------------------------------------------------
/chapter10/README.md:
--------------------------------------------------------------------------------
1 | # 第十章
2 |
3 | 适配器模式
4 |
5 | 将一个类(对象)的接口(方法或属性)转化成另外一个接口,以满足用户需求。
6 |
7 | 类(对象)之间接口的不兼容问题可以通过适配器模式解决
8 |
9 | * 1.js - 适配器模式
10 | * 2.js - 参数适配器
11 | * 3.js - 数据适配器
--------------------------------------------------------------------------------
/chapter2/README.md:
--------------------------------------------------------------------------------
1 | # 第二章
2 |
3 | 面对对象编程
4 |
5 | * 1.js - 闭包
6 | * 2.js - 创建对象的安全模式
7 | * 3.js - 类式继承(有缺陷的继承,不推荐使用)
8 | * 4.js - 构造函数继承(有缺陷的继承,不推荐使用)
9 | * 5.js - 组合继承(有缺陷)
10 | * 6.js - 终极继承者
--------------------------------------------------------------------------------
/chapter25/README.md:
--------------------------------------------------------------------------------
1 | # 第二十五章
2 |
3 | 迭代器模式(Iterator)
4 |
5 | 在不暴露对象内部结构的同时,可以顺序地访问聚合对象内部的元素
6 |
7 | * 1.js - 迭代器模式(一个幻灯片的基类案例)
8 | * 2.js - forEach的实现
9 | * 3.js - 对象迭代器的实现
10 | * 4.js - 取值器
--------------------------------------------------------------------------------
/chapter33/README.md:
--------------------------------------------------------------------------------
1 | # 第三十三章
2 |
3 | 参与者模式(participator)
4 |
5 | 在特定的作用域中执行给定的函数,并将参数原封不动地传递
6 |
7 | * 1.js - bind
8 | * 2.js - bind应用于事件
9 | * 3.js - 原声bind写法
10 | * 4.js - 函数柯里化
11 | * 5.js - 重构bind
--------------------------------------------------------------------------------
/chapter33/3.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var obj = {
4 | name: 'berwin'
5 | };
6 |
7 | function test() {
8 | console.log(this)
9 | }
10 |
11 | var a = test.bind(obj);
12 |
13 | a(); // { name: 'berwin' }
--------------------------------------------------------------------------------
/chapter17/README.md:
--------------------------------------------------------------------------------
1 | # 第十七章
2 |
3 | 观察者模式(Observer):又叫发布-订阅者模式(Publish/Subscribe)或消息机制,它定义了一种一对多的关系,让多个观察者对象同时监听某一个主体对象,这个主体对象的状态发生变化时就会通知所有的观察者对象,使得它们能够自动更新自己。
4 |
5 | * 1.js - 观察者模式
6 | * 2.js - 观察者模式在实际应用中的例子
7 | * 3.js - 老师和学生的故事。。。
--------------------------------------------------------------------------------
/chapter22/README.md:
--------------------------------------------------------------------------------
1 | # 第二十二章
2 |
3 | 访问者模式(Visitor):针对于对象结构中的元素,定义在不改变该对象的前提下访问结构中元素的新方法。
4 |
5 | * 1.js - 访问者模式
6 | * 2.js - 访问者模式2
7 |
8 | 访问者模式解决数据与数据的操作方法之间的耦合,将数据的操作方法独立于数据,使其可以自由化演变。(我觉得本章主要讲的就是Object.prototype.toString.call这样的使用方式)
--------------------------------------------------------------------------------
/chapter20/README.md:
--------------------------------------------------------------------------------
1 | # 第二十章
2 |
3 | 责任链模式(Chain of Responsibility):解决请求的发送者与请求的接受者之间的耦合,通过职责链上的多个对象对分解请求流程,实现请求在多个对象之间的传递,直到最后一个对象完成请求的处理。
4 |
5 | * 1.js - 责任链模式
6 |
7 | 责任链模式定义了请求的传递方向,通过多个函数对请求的传递,实现一个复杂的逻辑操作。因此责任链模式将负责的需求颗粒化逐一实现每个函数分内的需求,并将请求顺序地传递。
--------------------------------------------------------------------------------
/chapter22/1.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | function bindIEEvent(dom, type, fn, data) {
4 | var data = data || {};
5 |
6 | dom.attachEvent('on' + type, function(e) {
7 | fn.call(dom, e, data);
8 | });
9 | }
10 |
11 | // 我觉得这一章主要讲的是 call 的应用。。
--------------------------------------------------------------------------------
/chapter25/2.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var forEach = function(arr, fn) {
4 | for (var i = 0; i < arr.length; i++) {
5 | fn(arr[i], i, arr);
6 | }
7 | };
8 |
9 | forEach([1,2,3,4], function(item, i, arr) {
10 | console.log(item, i, arr);
11 | });
--------------------------------------------------------------------------------
/chapter12/README.md:
--------------------------------------------------------------------------------
1 | # 第十二章
2 |
3 | 装饰者模式
4 |
5 | 在不改变原对象的基础上,通过对其进行封装扩展(添加属性和方法)使原有对象可以满足用户的更复杂的需求。
6 |
7 | 同样对原有对象进行扩展的还有适配器模式,所不同的是适配器进行扩展很多时候是对对象内部的重组,因此了解其自身结构是必须的。而装饰者对对象的扩展是一种良性扩展,不用了解其具体实现,只是在外部进行了一次封装扩展,这又是对原有功能完整性的一种保护。
8 |
9 | * 1.js - 装饰者模式(对原有对象的属性与方法的添加)
--------------------------------------------------------------------------------
/chapter25/3.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var eachObject = function(obj, fn) {
4 | for (var i in obj) {
5 | fn(obj[i], i, obj);
6 | }
7 | };
8 |
9 | eachObject({a: '123', b: '456', c: '789'}, function(item, key, obj) {
10 | console.log(item, key, obj);
11 | });
--------------------------------------------------------------------------------
/chapter23/README.md:
--------------------------------------------------------------------------------
1 | # 第二十三章
2 |
3 | 中介者模式(Mediator)
4 |
5 | 通过终结者对象封装一系列对象之间的交互,使对象之间不再相互引用,降低它们之间的耦合。有时中介者对象也可改变对象之间的交互。
6 |
7 | * 1.js - 中介者模式
8 | * 2.js - 中介者模式(实际中的例子)
9 |
10 | 个人理解:虽然跟观察者模式有点像,但还是不一样的,观察者模式是双向的,订阅者也可以是发布者,而中介者模式的发布者有中介对象统一发布。。
11 |
12 | 中介者是单向的,类似于执行某个事件,然后所有订阅过该事件的都会执行。
--------------------------------------------------------------------------------
/chapter10/3.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | function arrToObj(arr) {
4 | return {
5 | name: arr[0],
6 | type: arr[1],
7 | title: arr[2],
8 | data: arr[3]
9 | };
10 | }
11 |
12 | var arr = ['javascript', 'book', '前端编程语言', '12月1日'];
13 |
14 | var obj = arrToObj(arr);
15 |
16 | console.log(obj);
--------------------------------------------------------------------------------
/chapter1/1.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var check = {
4 | checkName: function() {
5 | // 验证姓名
6 | },
7 |
8 | checkEmail: function() {
9 | // 验证邮箱
10 | },
11 |
12 | checkPassword: function() {
13 | // 验证密码
14 | }
15 | };
16 |
17 |
18 | var ck = check.checkName();
19 | console.log( ck );
--------------------------------------------------------------------------------
/chapter1/2.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var check = function() {
4 | return {
5 | checkName: function() {
6 | // 验证姓名
7 | },
8 |
9 | checkEmail: function() {
10 | // 验证邮箱
11 | },
12 |
13 | checkPassword: function() {
14 | // 验证密码
15 | }
16 | }
17 | };
18 |
19 | var a = check();
20 | a.checkName();
--------------------------------------------------------------------------------
/chapter36/test/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | test
6 |
7 |
8 |
9 |
14 |
15 |
--------------------------------------------------------------------------------
/chapter2/2.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var Book = function(title, time, type) {
4 | if (this instanceof Book) {
5 | this.title = title;
6 | this.time = time;
7 | this.type = type;
8 | } else {
9 | return new Book(title, time, type);
10 | }
11 | };
12 |
13 | var book = Book('Javascript', '2015', 'js');
14 |
15 | console.log(book);
--------------------------------------------------------------------------------
/chapter33/1.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | function bind(fn, context) {
4 | return function () {
5 | return fn.apply(context, arguments);
6 | }
7 | }
8 |
9 | // 测试
10 |
11 | var obj = {
12 | name: 'berwin'
13 | };
14 |
15 | function test(age) {
16 | console.log(this.name, age);
17 | }
18 |
19 | var a = bind(test, obj);
20 | a(20); // berwin 20
--------------------------------------------------------------------------------
/chapter1/3.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var Check = function() {
4 | this.checkName = function() {
5 | console.log('验证姓名');
6 | };
7 |
8 | this.checkEmail = function() {
9 | console.log('校验邮箱');
10 | };
11 |
12 | this.checkPassword = function() {
13 | console.log('校验密码');
14 | };
15 | };
16 |
17 | var a = new Check();
18 | a.checkName();
--------------------------------------------------------------------------------
/chapter1/4.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var Check = function() {};
4 |
5 | Check.prototype = {
6 | checkName: function() {
7 | console.log('校验姓名');
8 | },
9 |
10 | checkEmail: function () {
11 | console.log('校验邮箱');
12 | },
13 |
14 | checkPassword: function () {
15 | console.log('校验密码');
16 | }
17 | };
18 |
19 | var a = new Check();
20 | a.checkName();
--------------------------------------------------------------------------------
/chapter21/README.md:
--------------------------------------------------------------------------------
1 | # 第二十一章
2 |
3 | 命令模式(Command):将请求与实现解耦,并封装成独立对象,从而使不同的请求对客户端的实现参数化。
4 |
5 | * 1.js - 命令模式
6 |
7 | 命令模式是将执行的命令封装,解决命令的发起者与命令的执行者之间的耦合。每一条命令实质上是一个操作。命令的使用者不必要了解命令的执行者(命令对象)的命令接口是如何实现的,命令式如何接收的,命令式如何执行的。所有的命令都被存储在命令对象中。
8 |
9 | 命令模式的有点自然是解决命令使用者之间的耦合。新的命令很容易加入到命令系统中,供使用者使用。命令的使用具有一致性,多数的命令在一定程度上是简化操作方法的使用的。
10 |
11 | 命令模式是对一些操作的封装,这就造成每执行一次操作都要调用一次命令对象,增加了系统的复杂度。
--------------------------------------------------------------------------------
/chapter24/1.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // 背景:上一页下一页
4 |
5 | function Page() {
6 | var cache = {};
7 |
8 | return function(page, fn) {
9 | // 如果有缓存
10 | if (cache[page]) {
11 | fn && fn(cache[page]);
12 | } else {
13 | $.get('./data/getxxx').success(function(data) {
14 | cache[page] = data;
15 | fn && fn(data);
16 | });
17 | }
18 | }
19 | }
--------------------------------------------------------------------------------
/chapter1/6.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | Function.prototype.addMethod = function(name, fn) {
4 | this.prototype[name] = fn;
5 |
6 | return this;
7 | };
8 |
9 | var Methods = function() {};
10 |
11 | Methods.addMethod('checkName', function() {
12 | console.log('校验姓名');
13 | }).addMethod('checkEmail', function() {
14 | console.log('校验邮箱');
15 | });
16 |
17 | var a = new Methods();
18 | a.checkName();
--------------------------------------------------------------------------------
/chapter3/2.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | function createBook(name, time, type) {
4 | var o = {
5 | name: name,
6 | time: time,
7 | type: type,
8 | getName: function() {
9 | return this.name;
10 | }
11 | };
12 |
13 | return o;
14 | }
15 |
16 | var book1 = createBook('javascript', '2015', 'js');
17 | var book2 = createBook('Nodejs', '2015', 'Nodejs');
18 |
19 | console.log(book2);
--------------------------------------------------------------------------------
/chapter8/2.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var Config = (function() {
4 | // 私有变量
5 | var config = {
6 | MAX_NUM: 100,
7 | MIN_NUM: 1,
8 | COUNT: 1000
9 | };
10 |
11 | // 返回取值器对象
12 | return {
13 | // 取值器方法
14 | get: function(name) {
15 | return config[name] ? config[name] : null;
16 | }
17 | }
18 | })();
19 |
20 | var count = Config.get('COUNT');
21 | console.log(count);
--------------------------------------------------------------------------------
/chapter8/1.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var A = {
4 | Util: {
5 | util_method1: function() {},
6 | util_method2: function() {}
7 | },
8 | Tool: {
9 | tool_method1: function() {},
10 | tool_method2: function() {}
11 | },
12 | Ajax: {
13 | get: function() {},
14 | post: function() {}
15 | },
16 | others: {
17 | // ...
18 | }
19 | };
20 |
21 | A.Util.util_method2();
22 | A.Tool.tool_method1();
23 | A.Ajax.get();
--------------------------------------------------------------------------------
/chapter33/4.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | function curry(fn) {
4 | var slice = Array.prototype.slice;
5 | var args = slice.call(arguments, 1);
6 | return function() {
7 | var addArgs = slice.call(arguments);
8 | var allArgs = args.concat(addArgs);
9 | return fn.apply(null, allArgs);
10 | }
11 | }
12 |
13 | // 测试
14 | function add(num1, num2) {
15 | return num1 + num2;
16 | }
17 |
18 | var test = curry(add, 5);
19 | console.log( test(5) ); // 10
--------------------------------------------------------------------------------
/chapter1/5.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var Check = function() {};
4 |
5 | Check.prototype = {
6 | checkName: function () {
7 | console.log('校验姓名');
8 |
9 | return this;
10 | },
11 |
12 | checkEmail: function() {
13 | console.log('校验邮箱');
14 |
15 | return this;
16 | },
17 |
18 | checkPassword: function() {
19 | console.log('校验密码');
20 |
21 | return this;
22 | }
23 | };
24 |
25 | var a = new Check();
26 | a.checkName().checkEmail().checkPassword();
--------------------------------------------------------------------------------
/chapter4/1.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | var Factory = function(type, text) {
3 | if (this instanceof Factory) {
4 | this[type](text);
5 | } else {
6 | return new Factory(type, text);
7 | }
8 | };
9 |
10 | Factory.prototype = {
11 | javascript: function(text) {
12 | console.log(text + 'javascript');
13 | },
14 | nodejs: function(text) {
15 | console.log(text + 'nodejs');
16 | }
17 | };
18 |
19 | Factory('javascript', '万能的');
20 |
21 | // 好处是增加基类时,不需要在修改 Factory 了
--------------------------------------------------------------------------------
/chapter28/2.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // 通过事件委托为 当前页面不存在的元素 绑定事件
4 |
5 | var article = document.getElementById('article');
6 | article.onclick = function(e) {
7 | var event = e || event;
8 | var target = event.target || event.srcElement;
9 |
10 | if (target.nodeName.toLowerCase() === 'p') {
11 | target.innerHTML = '我要改变这段内容';
12 | }
13 | };
14 |
15 | var p = document.createElement('p');
16 | p.innerHTML = '新增一段内容';
17 | article.appendChild(p);
18 |
19 | // 测试html
20 | // 呵呵哒
--------------------------------------------------------------------------------
/chapter28/1.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // bad
4 | var ul = document.getElementById('container');
5 | var li = ul.getElementsByTagName('li');
6 |
7 | for (var i = 0; i < li.length; i++) {
8 | li[i].onclick = function() {
9 | this.style.backgroundColor = 'grey';
10 | };
11 | }
12 |
13 | // good
14 | ul.onclick = function(e) {
15 | var event = e || event;
16 | var target = e.target || e.srcElement;
17 |
18 | if (target.nodeName.toLowerCase() === 'li') {
19 | target.style.backgroundColor = 'grey';
20 | }
21 | };
--------------------------------------------------------------------------------
/chapter33/5.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | function bind(fn, context) {
4 | var slice = Array.prototype.slice;
5 | var args = slice.call(arguments, 2);
6 |
7 | return function() {
8 | var addArgs = slice.call(arguments);
9 | var allArgs = args.concat(addArgs);
10 |
11 | return fn.apply(context, allArgs);
12 | }
13 | }
14 |
15 | var btn = document.getElementById('btn');
16 |
17 | var obj = {
18 | name: 'berwin'
19 | };
20 |
21 | function demo(obj, e) {
22 | console.log(arguments);
23 | }
24 |
25 | var test = bind(demo, btn, obj);
26 |
27 | btn.addEventListener('click', test);
--------------------------------------------------------------------------------
/chapter28/3.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // 测试html
4 |
5 | /*
6 |
7 |
8 |
9 | */
10 |
11 | var g = function(id) {
12 | return document.getElementById(id);
13 | };
14 |
15 | g('btn').onclick = function() {
16 | g('container').innerHTML = '触发了事件';
17 | };
18 |
19 | // IE低版本问题
20 | // 触发事件时,会把按钮自身替换掉,事件并没有清除,所以会泄露到内存中
21 |
22 |
23 | // good
24 | g('container').onclick = function(e) {
25 | var target = e && e.target || event.srcElement;
26 |
27 | if (target.id === 'btn') {
28 | g('container').innerHTML = '触发了事件';
29 | }
30 | };
31 |
--------------------------------------------------------------------------------
/chapter8/3.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // 惰性载入单例
4 | var LazySingle = (function() {
5 |
6 | // 单例实例引用
7 | var _instance = null;
8 |
9 | // 单例
10 | function Single() {
11 | // 这里定义私有属性和方法
12 | return {
13 | publicMethod: function() {},
14 | publicProperty: '1.0'
15 | }
16 | }
17 |
18 | return function() {
19 |
20 | if (!_instance) {
21 | _instance = Single();
22 | }
23 |
24 | // 返回单例
25 | return _instance;
26 | }
27 | })();
28 |
29 |
30 | console.log( LazySingle().publicProperty ); // 1.0
31 | console.log( LazySingle() === LazySingle() ); // true
--------------------------------------------------------------------------------
/chapter9/1.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /*
4 | * 外观模式可以简化底层接口复杂性,也可以解决浏览器兼容性问题
5 | */
6 |
7 | // 外观模式实现
8 | function addEvent(dom, type, fn) {
9 |
10 | if (dom.addEventListener) {
11 | dom.addEventListener(type, fn, false);
12 | } else if (dom.attachEvent) {
13 | dom.attachEvent('on' + type, fn);
14 | } else {
15 | dom['on' + type] = fn;
16 | }
17 | }
18 |
19 | var myInput = document.getElementById('myinput');
20 |
21 | addEvent(myInput, 'click', function() {
22 | console.log('绑定第一个事件');
23 | });
24 |
25 | addEvent(myInput, 'click', function() {
26 | console.log('绑定第二个事件');
27 | });
--------------------------------------------------------------------------------
/chapter2/5.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // 声明父类
4 | function SuperClass(name) {
5 | this.name = name;
6 | this.books = ['Javascript', 'html', 'css'];
7 | }
8 |
9 | // 父类原型公有方法
10 | SuperClass.prototype.showName = function() {
11 | return this.name;
12 | };
13 |
14 | // 声明子类
15 | function SubClass(name, time) {
16 | SuperClass.call(this, name);
17 |
18 | this.time = time;
19 | }
20 |
21 | // 类式继承
22 | SubClass.prototype = new SuperClass();
23 |
24 | // 子类原型方法
25 | SubClass.prototype.getTime = function() {
26 | return this.time;
27 | };
28 |
29 | var a = new SubClass('Javascript', '2015');
30 | console.log(a)
31 |
32 | // 有缺陷 - 父类构造函数调用两遍
--------------------------------------------------------------------------------
/chapter2/4.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | function SuperClass(id) {
4 | this.books = ['Javascript', 'html', 'css'];
5 |
6 | // 值类型公有熟悉
7 | this.id = id;
8 | }
9 |
10 | SuperClass.prototype.showBooks = function() {
11 | console.log(this.books);
12 | };
13 |
14 | // 声明子类
15 | function SubClass(id){
16 | // 继承父类
17 | SuperClass.call(this, id);
18 | }
19 |
20 | // 创建第一个子类的实例
21 | var instance1 = new SubClass(10);
22 |
23 | // 创建第二个子类的实例
24 | var instance2 = new SubClass(11);
25 |
26 | instance1.books.push('设计模式');
27 |
28 | console.log(instance1);
29 | console.log(instance2);
30 |
31 | // 有缺陷 - 父类的原型方法不会被子类继承,只是由于父类中是给this绑定属性的,所以子类自然就继承了父类的共有属性,也可以说把父类的属性复制给子类
--------------------------------------------------------------------------------
/chapter13/2.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // 多维变量类
4 | // 运动单元
5 | function Speed(x, y) {
6 | this.x = x;
7 | this.y = y;
8 | }
9 | Speed.prototype.run = function() {
10 | console.log('跑起来');
11 | };
12 |
13 | // 着色单元
14 | function Color(cl) {
15 | this.color = cl;
16 | }
17 | Color.prototype.draw = function() {
18 | console.log('绘制色彩');
19 | };
20 |
21 |
22 | function Ball(x, y, c) {
23 | // 实现运动单元
24 | this.speed = new Speed(x, y);
25 | // 实现着色单元
26 | this.color = new Color(c);
27 | };
28 | Ball.prototype.init = function() {
29 | // 实现运动
30 | this.speed.run();
31 | // 实现着色
32 | this.color.draw();
33 | };
34 |
35 | var a = new Ball(1,2,'red');
36 | a.init();
--------------------------------------------------------------------------------
/chapter33/2.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | function bind(fn, context) {
4 | return function () {
5 | return fn.apply(context, arguments);
6 | }
7 | }
8 |
9 | var btn = document.getElementById('btn');
10 | var p = document.getElementById('p');
11 |
12 | function demoFn() {
13 | console.log(arguments, this);
14 | btn.removeEventListener('click', bindFn);
15 | }
16 |
17 | var bindFn = bind(demoFn, p);
18 |
19 | btn.addEventListener('click', bindFn, false);
20 |
21 | /*
22 |
23 | // 另一种简单的写法
24 | function test() {
25 | (function() {
26 | console.log(this)
27 | btn.removeEventListener('click', test);
28 | }).call(p);
29 | }
30 |
31 | btn.addEventListener('click', test, false);
32 |
33 | */
--------------------------------------------------------------------------------
/chapter10/2.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // 背景:如果方法需要传入很多参数,那么记住这些参数的顺序是很难的,所以我们经常是以一个参数对象方式传入的。
4 |
5 | function a(name, title, age, color, size, prize) {}
6 |
7 | /*
8 | * obj.name: name
9 | * obj.title: title
10 | * obj.age: age
11 | * obj.color: color
12 | * obj.size: size
13 | * obj.prize: prize
14 | */
15 |
16 | function a(obj) {}
17 |
18 | // 但是调用它的时候不知道传递的参数是否完整,此时我们通常的做法是用适配器来适配传入的参数对象
19 |
20 | function a(obj) {
21 | var _default = {
22 | name: '雨夜清荷',
23 | title: '设计模式',
24 | age: '20',
25 | color: 'pink',
26 | size: 100,
27 | prize: 50
28 | };
29 |
30 | for (var i in obj) {
31 | _default[i] = obj[i] || _default[i];
32 | }
33 |
34 | // code ....
35 | }
--------------------------------------------------------------------------------
/chapter24/2.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var Cache = (function () {
4 | var _cache = {};
5 |
6 | return {
7 | /*
8 | * 设置缓存
9 | *
10 | * key 键
11 | * data 缓存数据
12 | * cover 是否覆盖(默认不覆盖)
13 | */
14 | set: function(key, data, cover) {
15 | if (!_cache[key] || cover) {
16 | _cache[key] = data;
17 | }
18 | },
19 |
20 | /*
21 | * 获取缓存
22 | */
23 | get: function(key) {
24 | return _cache[key];
25 | },
26 |
27 | /*
28 | * 清除缓存
29 | */
30 | del: function(key) {
31 | delete _cache[key];
32 | }
33 | }
34 | })();
35 |
36 |
37 | Cache.set('test', {name: 'berwin'});
38 | console.log(Cache.get('test'));
39 |
40 | Cache.del('test');
41 | console.log(Cache.get('test'));
--------------------------------------------------------------------------------
/chapter18/1.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // 这是一个反面教材
4 |
5 | // 以超级玛丽为例子
6 |
7 | var lastAction = '';
8 |
9 | function changeMarry(action) {
10 | if (action == 'jump') {
11 | // 跳跃的动作
12 | } else if (action == 'move') {
13 | // 移动动作
14 | } else {
15 | // 默认情况
16 | }
17 |
18 | lastAction = action;
19 | }
20 |
21 | // 符合动作对条件判断的开销是翻倍的
22 |
23 | var lastAction1 = '';
24 | var lastAction2 = '';
25 |
26 | function changeMarry2(action1, action2) {
27 | if (action1 === 'shoot') {
28 | // 射击动作
29 | } else if (action1 === 'move' && action2 === 'shoot') {
30 | // 移动中射击
31 | } else if (action1 === 'jump' && action2 === 'shoot') {
32 | // 跳跃中射击
33 | }
34 |
35 | // 保留上一个动作
36 | lastAction1 = action1 || '';
37 | lastAction2 = action2 || '';
38 | }
--------------------------------------------------------------------------------
/chapter25/4.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var a = {
4 | common: {},
5 | client: {
6 | user: {
7 | username: 'berwin',
8 | uid: '123'
9 | }
10 | },
11 | server: {}
12 | };
13 |
14 | // 如果不知道服务器是否会将该属性或者该属性的上级属性正确的打印到页面中,直接获取属性会导致报错,所以每次操作都要一层一层做安全检查 var test = a && a.client && a.client.user && a.client.user.username;
15 |
16 | // 通过迭代器我们即可减少编写这类校验代码
17 | var getter = function(data, key) {
18 | if (!data) return undefined;
19 |
20 | var result = data;
21 |
22 | var keys = key.split('.');
23 |
24 | for (var i = 0; i < keys.length; i++) {
25 | if (result[keys[i]]) {
26 | result = result[keys[i]];
27 | } else {
28 | return undefined;
29 | }
30 | }
31 |
32 | return result;
33 | }
34 |
35 | console.log( getter(a, 'client.user.username') ); // berwin
--------------------------------------------------------------------------------
/chapter23/1.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // 中介者对象
4 | var Mediator = (function() {
5 | // 消息对象
6 | var _msg = {};
7 |
8 | return {
9 | subscribe: function(type, action) {
10 | if (_msg[type]) {
11 | _msg[type].push(action);
12 | } else {
13 | _msg[type] = [];
14 | _msg[type].push(action);
15 | }
16 | },
17 |
18 | send: function(type) {
19 | if (_msg[type]) {
20 | for (var i = 0; i < _msg[type].length; i++) {
21 | _msg[type][i] && _msg[type][i]();
22 | }
23 | }
24 | }
25 | };
26 | })();
27 |
28 | // 单元测试
29 |
30 | // 订阅
31 | Mediator.subscribe('demo', function() {
32 | console.log('first');
33 | });
34 |
35 | Mediator.subscribe('demo', function() {
36 | console.log('second');
37 | });
38 |
39 | Mediator.send('demo');
--------------------------------------------------------------------------------
/chapter32/1.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // 背景:每次执行方法都要进行一次判定,但其实是可以优化的
4 |
5 |
6 | var A = {};
7 |
8 | // bad
9 | A.on = function(dom, type, fn) {
10 | if (dom.addEventListener) {
11 | dom.addEventListener(type, fn, false);
12 | } else if (dom.attachEvent) {
13 | dom.attachEvent(type, fn);
14 | } else {
15 | dom['on' + type] = fn;
16 | }
17 | };
18 |
19 | console.log(A.on)
20 |
21 | // bood
22 | A.on = (function(dom) {
23 | if (dom.addEventListener) {
24 | return function(dom, type, fn) {
25 | dom.addEventListener(type, fn, false);
26 | }
27 | } else if (dom.attachEvent) {
28 | return function(dom, type, fn) {
29 | dom.attachEvent(type, fn);
30 | }
31 | } else {
32 | return function(dom, type, fn) {
33 | dom['on' + type] = fn;
34 | }
35 | }
36 | })(document);
37 |
38 | console.log(A.on);
--------------------------------------------------------------------------------
/chapter19/2.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var InputStrategy = (function() {
4 | var strategy = {
5 | isNumber: function(value) {
6 | return Object.prototype.toString.call(value) === '[object Array]';
7 | },
8 | phone: function(value) {
9 | return /^1[3578]\d{9}$/.test(value);
10 | }
11 | };
12 |
13 | return {
14 | check: function(type, value) {
15 | // 去除首尾空白符
16 | value = value.replace(/^\s+|\s+$/g, '');
17 |
18 | return strategy[type] ? strategy[type](value) : '没有该类型的检测方法';
19 | },
20 |
21 | // 添加策略
22 | addStrategy: function(type, fn) {
23 | strategy[type] = fn;
24 | }
25 | }
26 | })();
27 |
28 | InputStrategy.addStrategy('mail', function(value) {
29 | return /^(\w+)(@\w+)(\.\w+)+$/.test(value);
30 | });
31 |
32 | var is = InputStrategy.check('mail', 'abc@gmail.com');
33 |
34 | console.log(is);
--------------------------------------------------------------------------------
/chapter32/2.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var A = {};
4 |
5 | // bad
6 | A.on = function(dom, type, fn) {
7 | if (dom.addEventListener) {
8 | dom.addEventListener(type, fn, false);
9 | } else if (dom.attachEvent) {
10 | dom.attachEvent(type, fn);
11 | } else {
12 | dom['on' + type] = fn;
13 | }
14 | };
15 |
16 | // bood
17 |
18 | A.on = function(dom, type, fn) {
19 | if (dom.addEventListener) {
20 | A.on = function(dom, type, fn) {
21 | dom.addEventListener(type, fn, false);
22 | };
23 | } else if (dom.attachEvent) {
24 | A.on = function(dom, type, fn) {
25 | dom.attachEvent(type, fn);
26 | };
27 | } else {
28 | A.on = function(dom, type, fn) {
29 | dom['on' + type] = fn;
30 | };
31 | }
32 |
33 | A.on(dom, type, fn);
34 | }
35 |
36 | console.log(A.on)
37 |
38 | A.on(document, 'click', function() {});
39 |
40 | console.log(A.on)
--------------------------------------------------------------------------------
/chapter28/4.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // bad
4 | $.get('/banner', function(result) {
5 | // banner...
6 | });
7 |
8 | $.get('/aside', function(result) {
9 | // aside...
10 | });
11 |
12 | $.get('/article', function(result) {
13 | // article...
14 | });
15 |
16 | $.get('/member', function(result) {
17 | // member...
18 | });
19 |
20 | $.get('/message', function(result) {
21 | // message...
22 | });
23 |
24 | // good
25 | var Deal = {
26 | banner: function(result) {
27 | // banner...
28 | },
29 | aside: function(result) {
30 | // aside...
31 | },
32 | article: function(result) {
33 | // article...
34 | },
35 | member: function(result) {
36 | // member...
37 | },
38 | message: function(result) {
39 | // message...
40 | }
41 | };
42 |
43 | $.get('/deal', function(result) {
44 | for (var i in result) {
45 | Deal[i] && Deal[i](result[i]);
46 | }
47 | });
--------------------------------------------------------------------------------
/chapter12/1.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // 装饰者
4 | var decorate = function(id, fn) {
5 | // 获取事件源
6 | var dom = document.getElementById(id);
7 |
8 | // 若事件源已绑定事件
9 | if (typeof dom.onclick === 'function') {
10 |
11 | // 缓存事件源原有事件
12 | var oldClickFn = dom.onclick;
13 |
14 | // 为事件源定义新的事件
15 | dom.onclick = function() {
16 | // 事件源原有回调函数
17 | oldClickFn();
18 | // 执行事件源新增回调函数
19 | fn();
20 | };
21 |
22 | } else {
23 | // 如果未绑定事件,直接为事件源添加事件
24 | dom.onclick = fn;
25 | }
26 | };
27 |
28 |
29 |
30 | // 电话输入框功能装饰
31 | decorate('tel_input', function() {
32 | document.getElementById('tel_demo_text').style.display = 'none';
33 | });
34 |
35 |
36 |
37 |
38 | // 与适配器模式的区别:
39 | // 适配器方法使对原有对象适配,添加的方法与原有方法功能上大致相似。但是装饰者提供的方法与原来的方法功能项是有一定区别的。
40 | // 在装饰者模式中,不需要了解对象原有的功能,而且对象原有的方法照样可以原封不动的使用
41 | // 在适配器中增加的方法要调用原有的方法,需要了解原有方法实现的具体细节,而在装饰者中原封不动的使用,不需要知道原有方法实现的具体细节。
--------------------------------------------------------------------------------
/chapter7/2.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * 基于已经存在的模板对象克隆出新对象的模式
5 | *
6 | * 参数1,参数2,参数3...表示模板对象
7 | * 注意。这里对模板引用类型的属性实质上进行了浅复制(引用类型属性共享),可以根据需求自行深复制(引用类型属性复制)
8 | */
9 | function prototypeExtend() {
10 | // 缓存类
11 | var F = function() {};
12 |
13 | for (var i = 0; i < arguments.length; i++) {
14 | // 遍历每个末班对象中的属性
15 | for (var j in arguments[i]) {
16 | // 将属性复制到缓存类原型中
17 | F.prototype[j] = arguments[i][j];
18 | }
19 | }
20 |
21 | // 返回缓存类的一个实例
22 | return new F();
23 | }
24 |
25 | var penguin = prototypeExtend({
26 | speed: 20,
27 | swim: function() {
28 | console.log('游泳速度'+ this.speed);
29 | }
30 | },{
31 | run: function(speed) {
32 | console.log('奔跑速度'+ speed)
33 | }
34 | }, {
35 | jump: function() {
36 | console.log('跳跃动作');
37 | }
38 | });
39 |
40 | penguin.swim();
41 | penguin.run(10);
42 | penguin.jump();
43 |
44 | console.log(penguin.__proto__);
--------------------------------------------------------------------------------
/chapter19/README.md:
--------------------------------------------------------------------------------
1 | # 第十九章
2 |
3 | 策略模式(Strategy):将定义的一组算法封装起来,使其相互之间可以替换。封装的算法具有一定独立性,不会随客户端变化而变化。
4 |
5 |
6 | * 1.js - 策略模式
7 | * 2.js - 策略模式(表单验证)
8 |
9 | 策略模式最主要的特色是创建一系列策略算法,魅族算法处理的业务都是相同的,只是处理的过程或者处理的结果不一样,所以它们又是可以相互替换的,这样就解决了算法与使用者之间的耦合。在测试层面上讲,由于每组算法相互之间的独立性,该模式更方便与对每组算法进行单元测试,保证算法的质量。
10 |
11 | 对于策略模式的有点可以归纳为3点
12 |
13 | 1. 策略模式封装了一组代码族,并且封装的代码相互之间独立,便于对算法的重复引用,提高了算法的复用率
14 | 2. 策略模式与继承相比,在类的继承中继承的方法是被封装在类中,因此当需求很多算法时,就不得不创建出多种类,这样会导致算法与算法的使用者耦合在一起,不利于算法的独立演化,并且在类的外部改变类的算法难度也是极大的。
15 | 3. 同状态模式一样,策略模式也是一种优化分支判断语句的模式,采用策略模式对算法封装使得算法更利于维护。
16 |
17 | 当然,策略模式也有缺点。由于选择哪种算法的决定权在用户,所以对用户来说就必须了解每种算法的实现。这就增加了用户的使用成本。其次,由于每种算法间相互独立,这样对于一些复杂的算法处理相同逻辑的部分无法实现共享,这就会造成一些资源的浪费。当然你可以通过享元模式(第十三章)来解决。
18 |
19 | 对于分支语句的优化,目前为止已经学了3种,分别为工厂方法模式,状态模式与策略模式。对于工厂方法模式来说,它是一种创建型模式,它的最终目的是创建对象。而状态模式与策略模式都是行为性模式,不过在状态模式中,其核心是对状态的控制来决定表现行为,所以状态之间通常是不能相互替代的,否则将产生不同的行为结果。而策略模式核心是算法,由于每种算法都要处理的业务逻辑相同,因此他们可以相互替换,当然策略模式并不关心使用者的环境,因为同一种策略模式最宠产出的结果是一定的。
--------------------------------------------------------------------------------
/chapter2/1.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var Book = (function () {
4 |
5 | // 私有属性
6 | var bookNum = 0;
7 |
8 | // 私有方法
9 | function checkBook() {
10 | // ...
11 | }
12 |
13 | function _book(newID, newName, newPrice) {
14 |
15 | // 私有变量
16 | var name, price;
17 |
18 | // 静态私有方法
19 | function checkID(id) {}
20 |
21 | // 特权方法
22 | this.getName = function() {};
23 | this.getPrice = function() {};
24 | this.setName = function() {};
25 | this.setPrice = function() {};
26 |
27 | // 公有属性
28 | this.id = newID;
29 |
30 | // 公有方法
31 | this.copy = function() {};
32 | bookNum++;
33 | if(bookNum > 100) {
34 | throw new Error('我们仅出版100本书。');
35 | }
36 |
37 | // 构造器
38 | this.setName(name);
39 | this.setPrice(price);
40 | }
41 |
42 | _book.prototype = {
43 | // 静态公有属性
44 | isJSBook: false,
45 |
46 | // 静态公有方法
47 | display: function () {}
48 | };
49 |
50 | return _book;
51 |
52 | })();
--------------------------------------------------------------------------------
/chapter13/1.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var spans = document.getElementsByTagName('span');
4 |
5 | spans[0].onmouseover = function() {
6 | this.style.color = 'red';
7 | this.style.background = '#ddd';
8 | };
9 | spans[0].onmouseout = function() {
10 | this.style.color = '#333';
11 | this.style.background = '#f5f5f5';
12 | };
13 |
14 | spans[1].onmouseover = function() {
15 | this.getElementsByTagName('strong')[0].style.color = 'red';
16 | this.getElementsByTagName('strong')[0].style.background = '#ddd';
17 | };
18 | spans[1].onmouseout = function() {
19 | this.getElementsByTagName('strong')[0].style.color = '#333';
20 | this.getElementsByTagName('strong')[0].style.background = '#f5f5f5';
21 | };
22 |
23 | // 使用桥接模式后
24 | function changeColor(dom, color, bg) {
25 | dom.style.color = color;
26 | this.style.background = bg;
27 | }
28 |
29 | // 事件与业务逻辑的桥梁
30 | spans[0].onmouseover = function() {
31 | changeColor(this, 'red', '#ddd');
32 | };
33 | spans[0].onmouseout = function() {
34 | changeColor(this, '#333', '#f5f5f5');
35 | };
36 |
--------------------------------------------------------------------------------
/chapter19/1.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // 背景:过节商品打折,一部分商品5折出售,一部分8折出售,一部分商品9折出售,等到元旦,我们要搞一个幸运反馈活动,普通用户满100返30,高级VIP用户满100返50...
4 |
5 | // 价格策略对象
6 | var PriceStrategy = (function() {
7 | // 内部算法对象
8 | var stragtegy = {
9 |
10 | // 100返30
11 | return30: function(price) {
12 | return +price + parseInt(price / 100) * 30;
13 | },
14 |
15 | // 满100返50
16 | return50: function(price) {
17 | return +price + parseInt(price / 100) * 50;
18 | },
19 |
20 | // 九折
21 | percent90: function(price) {
22 | return 90 / 100 * +price;
23 | },
24 |
25 | // 八折
26 | percent80: function(price) {
27 | return 80 / 100 * +price;
28 | },
29 |
30 | // 五折
31 | percent50: function(price) {
32 | return 50 / 100 * +price;
33 | }
34 | };
35 |
36 | // 策略算法调用接口
37 | return function(algorithm, price) {
38 | // 如果算法存在,则调用算法,否则返回false
39 | return stragtegy[algorithm] && stragtegy[algorithm](price);
40 | }
41 | })();
42 |
43 | var price = PriceStrategy('return50', '314.67');
44 | console.log(price); // 464.67
--------------------------------------------------------------------------------
/chapter10/1.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // 定义框架
4 | var A = A || {};
5 |
6 | // 通过id获取元素
7 | A.g = function(id) {
8 | return document.getElementById(id);
9 | };
10 |
11 | // 为元素绑定事件
12 | A.on = function(id, type, fn) {
13 | // 如果传递参数是字符串则以id处理,否则以元素对象处理
14 | var dom = typeof id ==='string' ? this.g(id) : id;
15 |
16 | if (dom.addEventListener) {
17 | dom.addEventListener(type, fn, false);
18 | } else if (dom.attachEvent) {
19 | dom.attachEvent('on' + type, fn);
20 | } else {
21 | dom['on' + type] = fn;
22 | }
23 | };
24 |
25 | A.on(window, 'load', function() {
26 | // 按钮点击事件
27 | A.on('mybutton', 'click', function() {
28 | // xxx
29 | });
30 | });
31 |
32 |
33 |
34 | // 背景:忽然项目中想把依赖换成jQuery,但总不能所有的方法都用jQuery的语法重新写一遍,那就写个适配器吧~
35 |
36 | /********* 适配器(适配jQuery) *************/
37 |
38 | A.g = function(id) {
39 | // 通过jQuery获取jQuery对象,然后返回第一个成员
40 | return $(id).get(0);
41 | };
42 |
43 | A.on = function(id, type, fn) {
44 | // 如果传递参数是字符串则以id处理,否则以元素对象处理
45 | var dom = typeof id === 'string' ? $('#' + id) : $(id);
46 |
47 | // 绑定事件
48 | dom.on(type, fn);
49 | };
50 |
51 |
--------------------------------------------------------------------------------
/chapter22/2.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // 访问器
4 | var Visitor = (function() {
5 | return {
6 | splice: function() {
7 | // 获取参数,从第二个方法算起
8 | var args = Array.prototype.splice.call(arguments, 1);
9 |
10 | // 对第一个参数执行splice方法
11 | return Array.prototype.splice.apply(arguments[0], args);
12 | },
13 |
14 | push: function() {
15 | // 获取参数,从第二个方法算起
16 | var args = Array.prototype.splice.call(arguments, 1);
17 |
18 | return Array.prototype.push.apply(arguments[0], args);
19 | },
20 |
21 | pop: function() {
22 | return Array.prototype.pop.apply(arguments[0]);
23 | }
24 | };
25 | })();
26 |
27 | var a = {};
28 | console.log(a.length);
29 |
30 | Visitor.push(a, 1, 2, 3, 4, 5);
31 | console.log(a.length);
32 |
33 | Visitor.push(a, 6, 7, 8, 9);
34 | console.log('push:');
35 | console.log(a);
36 | console.log(a.length);
37 |
38 | Visitor.pop(a);
39 | console.log('pop:');
40 | console.log(a);
41 | console.log(a.length);
42 |
43 | Visitor.splice(a, 2, 2);
44 | console.log('splice:');
45 | console.log(a);
46 | console.log(a.length);
47 |
48 | // 我觉得本章主要讲的内容就是 call 和 apply 的应用
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Berwin
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/chapter39/1.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // 只是搭建一个大题的架构,落实到具体功能上的例子在书中查看~~
4 |
5 | var MVP = function () {};
6 |
7 | MVP.model = (function () {
8 | // 内部数据对象
9 | var M = {};
10 |
11 | // 服务端获取的数据,通常通过ajax获取并存储
12 | // 缓存起来,减少异步请求操作
13 | M.data = {};
14 |
15 | // 配置数据,页面加载时即提供
16 | M.conf = {};
17 |
18 | return {
19 | getData: function (m) {
20 | return M.data[m];
21 | },
22 | getConf: function (c) {
23 | return M.conf[c];
24 | },
25 | setData: function (m, v) {
26 | M.data[m] = v;
27 | return v;
28 | },
29 | setConf: function (c, v) {
30 | M.conf[c] = v;
31 | return v;
32 | }
33 | };
34 | })();
35 |
36 | MVP.view = (function () {
37 | return function (str) {
38 | var html = '';
39 |
40 | // 将参数字符串转换成期望模板
41 | return html;
42 | }
43 | })();
44 |
45 | MVP.presenter = (function () {
46 | var V = MVP.view;
47 | var M = MVP.model;
48 | var C = {};
49 |
50 | return {
51 | init: function () {
52 | for (var i in C) {
53 | C[i] && C[i](M, V, i);
54 | }
55 | }
56 | };
57 | })();
58 |
59 | MVP.init = function () {
60 | this.presenter.init();
61 | };
62 |
--------------------------------------------------------------------------------
/chapter2/3.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var SuperClass = function() {
4 | this.superValue = true;
5 | };
6 |
7 | // 为父类添加公有方法
8 | SuperClass.prototype.getSuperValue = function() {
9 | return this.superValue;
10 | };
11 |
12 | var SubClass = function() {
13 | this.subValue = false;
14 | };
15 |
16 | // 继承父类
17 | SubClass.prototype = new SuperClass();
18 |
19 | // 为子类添加公有方法
20 | SubClass.prototype.getSubValue = function() {
21 | return this.subValue;
22 | };
23 |
24 | var a = new SubClass();
25 |
26 | console.log('a.getSuperValue() =', a.getSuperValue()); // true
27 | console.log('a.getSubValue() =', a.getSubValue()); // false
28 | console.log('a.superValue =', a.superValue); // true
29 | console.log('a.subValue =', a.subValue); // false
30 |
31 | console.log('a instanceof SubClass =', a instanceof SubClass); // true
32 | console.log('a instanceof SuperClass =', a instanceof SuperClass); // true
33 | console.log('SubClass instanceof SuperClass =', SubClass instanceof SuperClass); // false
34 | console.log('SubClass.prototype instanceof SuperClass =', SubClass.prototype instanceof SuperClass); // true
35 |
36 | // 有缺陷,用new SubClass()创建两个实例时 a, b,这两个实例的属性是同一个,a修改属性superValue,b的superValue会被a修改
--------------------------------------------------------------------------------
/chapter38/1.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // 初始化MVC对象
4 | var MVC = MVC || {};
5 |
6 | // 数据模型层
7 | MVC.model = (function () {
8 | // 内部数据对象
9 | var M = {};
10 |
11 | // 服务端获取的数据,通常通过ajax获取并存储
12 | // 缓存起来,减少异步请求操作
13 | M.data = {};
14 |
15 | // 配置数据,页面加载时即提供
16 | M.conf = {};
17 |
18 | return {
19 | getData: function (m) {
20 | return M.data[m];
21 | },
22 | getConf: function (c) {
23 | return M.conf[c];
24 | },
25 | setData: function (m, v) {
26 | M.data[m] = v;
27 | return this;
28 | },
29 | setConf: function (c, v) {
30 | M.conf[c] = v;
31 | return this;
32 | }
33 | };
34 | })();
35 |
36 | // 视图层
37 | MVC.view = (function () {
38 | // 模型数据层对象操作方法引用
39 | var M = MVC.model;
40 |
41 | // 内部视图创建方法
42 | var V = {};
43 |
44 | return function (v) {
45 | // 根据视图名称返回视图(由于获取的是一个方法,所以需要执行一边方法获取视图)
46 | V[v]();
47 | };
48 |
49 | })();
50 |
51 | // 控制器层
52 | MVC.ctrl = (function () {
53 | // 模型数据层对象操作方法引用
54 | var M = MVC.model;
55 | // 视图层对象操作方法引用
56 | var V = MVC.view;
57 |
58 | // 控制器创建方法对象
59 | var C = {};
60 |
61 | // 执行
62 | for (var i in C) {
63 | C[i] && C[i]();
64 | }
65 | })();
66 |
--------------------------------------------------------------------------------
/chapter2/6.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // 原型式继承
4 | function inheritObject(o) {
5 | // 声明一个过渡函数
6 | function F() {}
7 |
8 | // 过渡对象的原型继承父对象
9 | F.prototype = o;
10 |
11 | // 返回过渡对象的一个实例,该实例的原型继承了父对象
12 | return new F();
13 | }
14 |
15 | /**
16 | * 寄生式继承 继承原型
17 | *
18 | * 传递参数 subClass 子类
19 | * 传递参数 superClass 父类
20 | */
21 | function inheritPrototype(subClass, superClass) {
22 | var p = new inheritObject(superClass.prototype);
23 |
24 | p.constructor = subClass;
25 |
26 | subClass.prototype = p;
27 | }
28 |
29 |
30 | // 定义父类
31 | var SuperClass = function(name) {
32 | this.name = name;
33 | this.colors = ['red', 'green', 'yellow'];
34 | };
35 |
36 | // 定义父类原型方法
37 | SuperClass.prototype.getName = function() {
38 | console.log(this.name);
39 | };
40 |
41 | // 定义子类
42 | var SubClass = function(name, time) {
43 | // 构造函数式继承
44 | SuperClass.call(this, name);
45 |
46 | // 子类新增属性
47 | this.time = time;
48 | };
49 |
50 | // 寄生式继承父类原型
51 | inheritPrototype(SubClass, SuperClass);
52 |
53 | // 子类新增原型方法
54 | SubClass.prototype.getTime = function() {
55 | console.log(this.time);
56 | };
57 |
58 | var a = new SubClass('javascript', '2015');
59 | var b = new SubClass('Nodejs', '2015');
60 |
61 | a.getName();
--------------------------------------------------------------------------------
/chapter3/1.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // 篮球基类
4 | var BasketBall = function() {
5 | this.intro = '篮球盛行于美国';
6 | };
7 |
8 | BasketBall.prototype = {
9 | getMember: function() {
10 | console.log('每个队伍需要5名队员');
11 | },
12 |
13 | getBallSize: function() {
14 | console.log('篮球很大');
15 | }
16 | };
17 |
18 | // 足球基类
19 | var FootBall = function() {
20 | this.intro = '足球在世界范围内很流行';
21 | };
22 |
23 | FootBall.prototype = {
24 | getMember: function() {
25 | console.log('每个队伍需要11名队员');
26 | },
27 |
28 | getBallSize: function() {
29 | console.log('足球很大');
30 | }
31 | };
32 |
33 | // 网球基类
34 | var Tennis = function() {
35 | this.intro = '每年有很多网球系列赛';
36 | }
37 |
38 | Tennis.prototype = {
39 | getMember: function() {
40 | console.log('每个队伍需要1名队员');
41 | },
42 |
43 | getBallSize: function() {
44 | console.log('网球很小');
45 | }
46 | };
47 |
48 | // 运动工厂
49 | var SportsFactory = function(name) {
50 | switch(name) {
51 | case 'NBA':
52 | return new BasketBall();
53 | case 'wordCup':
54 | return new FootBall();
55 | case 'FrenchOpen':
56 | return new Tennis();
57 | }
58 | };
59 |
60 | // 为NBA杯创建一个篮球,只需要记住运动工厂 SportsFactory,调用并创建
61 | var NBA = SportsFactory('NBA');
62 | console.log(NBA);
63 |
--------------------------------------------------------------------------------
/chapter7/1.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // 图片轮播类
4 | var LoopImages = function(imgArr, container) {
5 | this.imagesArray = imgArr; // 轮播图片组
6 | this.container = container; // 轮播图片容器
7 | };
8 |
9 | LoopImages.prototype = {
10 | // 创建轮播图片
11 | createImages: function() {
12 | console.log('LoopImages createImage function');
13 | },
14 |
15 | // 切换下一张图片
16 | changeImage: function() {
17 | console.log('LoopImages changeImage function');
18 | }
19 | };
20 |
21 | // 上下滑动切换类
22 | var SlideLoopImg = function(imgArr, container) {
23 | // 构造函数继承图片轮播类
24 | LoopImages.call(this, imgArr, container);
25 | };
26 |
27 | SlideLoopImg.prototype = new LoopImages();
28 |
29 | // 重写继承的切换下一张方法
30 | SlideLoopImg.prototype.changeImage = function() {
31 | console.log('SlideLoopImg changeImage function');
32 | };
33 |
34 | // 渐隐切换类
35 | var FadeLoopImg = function(imgArr, container, arrow) {
36 | LoopImages.call(this, imgArr, container);
37 |
38 | // 切换剪头私有变量
39 | this.arrow = arrow;
40 | };
41 |
42 | FadeLoopImg.prototype = new LoopImages();
43 | FadeLoopImg.prototype.changeImage = function() {
44 | console.log('FadeLoopImg changeImage function');
45 | };
46 |
47 |
48 | // 测试用例
49 | var fadeImg = new FadeLoopImg(['a.png', 'b.png'], 'slider', '123');
50 | console.log(fadeImg);
51 |
--------------------------------------------------------------------------------
/chapter31/1.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var A = A || {};
4 |
5 | // 主体展示区容器
6 | A.root = document.getElementById('container');
7 |
8 | A.formateString = function(tpl, data) {
9 | return tpl.replace(/\{#(\w+)#\}/g, function(match, key) {
10 | return typeof data[key] === undefined ? '' : data[key];
11 | });
12 | };
13 |
14 | A.strategy = {
15 | listPart: function(data) {
16 | var s = document.createElement('div');
17 | var list = data.list;
18 | var ul = '';
19 |
20 | var tpl = [
21 | '{#h2#}
',
22 | '{#p#}
',
23 | ''
24 | ].join('');
25 |
26 | var liTpl = [
27 | '',
28 | '{#strong#}',
29 | '{#span#}',
30 | ''
31 | ].join('');
32 |
33 | data.id && (s.id = data.id);
34 |
35 | for (var i = 0; i < list.length; i++) {
36 | if (list[i].strong || list[i].span) {
37 | ul += A.formateString(liTpl, list[i]);
38 | }
39 | }
40 |
41 | data.ul = ul;
42 |
43 | s.innerHTML = A.formateString(tpl, data);
44 |
45 | A.root.appendChild(s);
46 | }
47 | };
48 |
49 |
50 | A.strategy.listPart({h2: 'berwin', p: 'adfsf', list: [{strong: 'strong', span: 'span'}, {strong: 'strong1', span: 'span1'}]})
51 |
52 |
53 | // 测试html
54 | //
--------------------------------------------------------------------------------
/chapter17/1.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // 背景:评论+消息通知
4 |
5 | /*
6 | * 观察者模式
7 | *
8 | * 将观察者放在闭包中,当页面加载就立即执行
9 | */
10 | var Observer = (function() {
11 | // 防止消息队列暴漏而被篡改,故将消息容器作为静态私有变量保存。
12 | var __message = {};
13 |
14 | return {
15 | // 订阅
16 | subscribe: function(type, fn) {
17 | // 如果消息不存在则创建一个消息类型
18 | if (!__message[type]) {
19 | __message[type] = [fn];
20 | } else {
21 | // 将动作方法推送到消息对应的动作执行序列中
22 | __message[type].push(fn);
23 | }
24 | },
25 |
26 | // 取消订阅
27 | unsubscribe: function(type, fn) {
28 | if (!__message[type] || Object.prototype.toString.call(__message[type]) !== '[object Array]') return;
29 |
30 | for (var i = __message[type].length - 1; i >= 0; i--) {
31 | __message[type][i] === fn && __message[type].splice(i, 1);
32 | };
33 | },
34 |
35 | // 发布信息
36 | publish: function(type, args) {
37 | if (!__message[type]) return;
38 |
39 | // 定义消息信息
40 | var events = {
41 | type: type,
42 | args: args
43 | };
44 |
45 | // 执行注册的消息所对应的所有动作序列
46 | for (var i = 0; i < __message[type].length; i++) {
47 | __message[type][i].call(this, events);
48 | }
49 | }
50 | }
51 | })();
52 |
53 |
54 | /*
55 | * 拉出来溜溜
56 | */
57 |
58 | // 订阅
59 | Observer.subscribe('test', function(e) {
60 | console.log(e);
61 | });
62 |
63 | // 发布
64 | Observer.publish('test', {msg: '传递参数'});
--------------------------------------------------------------------------------
/chapter18/2.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // 超级玛丽的例子
4 |
5 | // 创建超级玛丽状态类
6 | var MarryState = function() {
7 | var _currentState = {};
8 |
9 | // 动作与状态方法映射
10 | var states = {
11 | jump: function() {
12 | // 跳跃
13 | console.log('jump');
14 | },
15 | move: function() {
16 | // 移动
17 | console.log('move');
18 | },
19 | shoot: function() {
20 | // 射击
21 | console.log('shoot');
22 | },
23 | squat: function() {
24 | // 蹲下
25 | console.log('squat');
26 | }
27 | };
28 |
29 | // 动作控制类
30 | var Action = {
31 | changeState: function() {
32 | var arg = arguments;
33 |
34 | // 重置内部状态
35 | _currentState = {};
36 |
37 | if (arg.length) {
38 | for (var i = 0; i < arg.length; i++) {
39 | _currentState[arg[i]] = true;
40 | }
41 | }
42 |
43 | return this;
44 | },
45 |
46 | goes: function() {
47 | console.log('触发一次动作');
48 |
49 | for (var i in _currentState) {
50 | states[i] && states[i]();
51 | }
52 |
53 | return this;
54 | }
55 | };
56 |
57 | return {
58 | change: Action.changeState,
59 | goes: Action.goes
60 | };
61 | };
62 |
63 |
64 | // 两种执行方式,可以直接执行状态类,也可以实例化状态类
65 | // 直接执行状态类:如果直接使用实例化类就只能自己使用,如果还有另一个人使用,就可能会修改状态类内部的状态
66 | // 实例化状态类:实例化状态类有一个好处就是 它是对状态类的复制,无论怎么使用,都不会影响我,
67 | var marry = new MarryState();
68 |
69 | marry.change('jump', 'shoot').goes().goes().change('shoot').goes();
70 |
--------------------------------------------------------------------------------
/chapter31/2.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var A = A || {};
4 |
5 | // 主体展示区容器
6 | A.root = document.getElementById('container');
7 |
8 | A.formateString = function(tpl, data) {
9 | return tpl.replace(/\{#(\w+)#\}/g, function(match, key) {
10 | return typeof data[key] === undefined ? '' : data[key];
11 | });
12 | };
13 |
14 | A.view = function(name) {
15 | if (Object.prototype.toString.call(name) === '[object Array]') {
16 | var tpl = '';
17 |
18 | for (var i = 0; i < name.length; i++) {
19 | tpl += A.view(name[i]);
20 | }
21 |
22 | return tpl;
23 | } else {
24 | return '<'+ name +'>{#'+ name +'#}'+ name +'>';
25 | }
26 | };
27 |
28 | A.strategy = {
29 | listPart: function(data) {
30 | var s = document.createElement('div');
31 | var list = data.list;
32 | var ul = '';
33 |
34 | var tpl = A.view(['h2', 'p', 'ul']);
35 |
36 | var li = A.view('li');
37 | var liSon = A.view(['strong', 'span']);
38 | var liTpl = A.formateString(li, {li: liSon});
39 |
40 | data.id && (s.id = data.id);
41 |
42 | for (var i = 0; i < list.length; i++) {
43 | if (list[i].strong || list[i].span) {
44 | ul += A.formateString(liTpl, list[i]);
45 | }
46 | }
47 |
48 | data.ul = ul;
49 |
50 | s.innerHTML = A.formateString(tpl, data);
51 |
52 | A.root.appendChild(s);
53 | }
54 | };
55 |
56 |
57 | A.strategy.listPart({h2: 'berwin', p: 'adfsf', list: [{strong: 'strong', span: 'span'}, {strong: 'strong1', span: 'span1'}]})
58 |
59 |
60 | // 测试html
61 | //
--------------------------------------------------------------------------------
/chapter16/2.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | function formateString(str, data) {
4 | return str.replace(/\{#(\w+)#\}/g, function(match, key) {
5 | return typeof data[key] === undefined ? '' : data[key];
6 | });
7 | }
8 |
9 | /*
10 | * 基础导航
11 | */
12 | var Nav = function(data) {
13 | // 基础导航样式模板
14 | var item = '{#name#}';
15 |
16 | // 创建字符串
17 | var html = '';
18 |
19 | // 格式化数据
20 | for (var i = 0; i < data.length; i++) {
21 | html += formateString(item, data[i]);
22 | }
23 |
24 | return html;
25 | };
26 |
27 |
28 | /*
29 | * 带有消息提醒信息导航
30 | */
31 | var NumNav = function(data) {
32 | var tpl = '{#num#}';
33 |
34 | for (var i = 0; i < data.length; i++) {
35 | data[i].name += formateString(tpl, data[i]);
36 | }
37 |
38 | // 继承继承类,并返回字符串
39 | return Nav.call(this, data);
40 | };
41 |
42 |
43 | /*
44 | * 带有链接地址的导航
45 | */
46 | var LinkNav = function(data) {
47 | var tpl = '{#link#}';
48 |
49 | for (var i = 0; i < data.length; i++) {
50 | data[i].name += formateString(tpl, data[i]);
51 | }
52 |
53 | return Nav.all(this, data);
54 | };
55 |
56 |
57 | // 获取导航容器
58 | var nav = document.getElementById('content');
59 |
60 | // 添加内容
61 | nav.innerHTML = NumNav([{
62 | href: 'http://hao.360.cn',
63 | title: '360导航',
64 | name: '360',
65 | num: '10'
66 | },{
67 | href: 'http://www.taobao.com',
68 | title: '淘宝商城',
69 | name: '淘宝',
70 | num: '2'
71 | },{
72 | href: 'http://www.qq.com',
73 | title: '腾讯首页',
74 | name: '腾讯',
75 | num: '3'
76 | }]);
77 |
--------------------------------------------------------------------------------
/chapter20/1.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // 背景:项目经理准备改善页面中的输入验证与输入提示交互体验,如用户在输入框输入信息后,在输入框的下面提示出一些备选项,当用户输入完成后,则要对用户输入的信息进行验证等。
4 |
5 |
6 | /*
7 | * 异步请求对象(伪代码)
8 | *
9 | * data 请求数据
10 | * dealType 相应数据处理对象
11 | * dom 事件源
12 | */
13 | var sendData = function(data, dealType, dom) {
14 |
15 | // ... 这是一个ajax请求代码
16 |
17 | // 请求成功之后回调函数
18 | var result = ['嘿嘿嘿', '哈哈哈', '呵呵呵'];
19 | dealData(result, dealType, dom);
20 | };
21 |
22 |
23 | /*
24 | * 处理响应数据
25 | *
26 | * data 相应数据
27 | * dealType 相应数据处理对象
28 | * dom 事件源
29 | */
30 | var dealData = function(data, dealType, dom) {
31 | var dataType = Object.prototype.toString.call(data);
32 |
33 | switch(dealType) {
34 | case 'sug':
35 |
36 | if (dataType === '[object Array]') {
37 | return createSug(data, dom);
38 | }
39 |
40 | if (dataType === '[object Object]') {
41 | var newData = [];
42 | for (var i in data) {
43 | newData.push(data[i]);
44 | }
45 |
46 | return createSug(newData, dom);
47 | }
48 |
49 | return createSug([data], dom);
50 |
51 | break;
52 | case 'validate':
53 | return createValidataResult(data, dom);
54 | break;
55 | }
56 | };
57 |
58 |
59 | /*
60 | * 创建提示框组件
61 | *
62 | * data 响应适配数据
63 | * dom 事件源
64 | */
65 | var createSug = function(data, dom) {
66 | var html = '';
67 |
68 | for (var i = 0; i < data.length; i++) {
69 | html += '' + data[i] + '';
70 | }
71 |
72 | dom.parentNode.getElementsByTagName('ul')[0].innerHTML = html;
73 | };
74 |
75 |
76 | /*
77 | * 创建校验组件
78 | *
79 | * data 响应适配数据
80 | * dom 事件源
81 | */
82 | var createValidataResult = function(data, dom) {
83 | // 显示校验结果
84 | dom.parentNode.getElementsByTagName('span')[0].innerHTML = data;
85 | };
86 |
--------------------------------------------------------------------------------
/chapter5/1.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var VehicleFactory = function(subClass, superType) {
4 |
5 | // 判断抽象工厂中是否有该抽象类
6 | if (typeof VehicleFactory[superType] === 'function') {
7 |
8 | // 缓存类
9 | function F() {}
10 |
11 | // 继承父类属性和方法
12 | F.prototype = new VehicleFactory[superType]();
13 |
14 | // 将子类constructor指向子类
15 | F.constructor = subClass;
16 |
17 | // 子类原型继承”父类“
18 | subClass.prototype = new F();
19 | } else {
20 | throw new Error('未创建该抽象类');
21 | }
22 | };
23 |
24 | // 小汽车抽象类
25 | VehicleFactory.Car = function() {
26 | this.type = 'car';
27 | };
28 |
29 | VehicleFactory.Car.prototype = {
30 | getPrice: function() {
31 | return new Error('抽象方法不能调用');
32 | },
33 | getSpeed: function() {
34 | return new Error('抽象方法不能调用');
35 | }
36 | };
37 |
38 | // 公交车抽象类
39 | VehicleFactory.Bus = function() {
40 | this.type = 'bus';
41 | };
42 |
43 | VehicleFactory.Bus.prototype = {
44 | getPrice: function() {
45 | return new Error('抽象方法不能调用');
46 | },
47 | getSpeed: function() {
48 | return new Error('抽象方法不能调用');
49 | }
50 | };
51 |
52 | // 货车抽象类
53 | VehicleFactory.Truck = function() {
54 | this.type = 'truck';
55 | };
56 |
57 | VehicleFactory.Truck.prototype = {
58 | getPrice: function() {
59 | return new Error('抽象方法不能调用');
60 | },
61 | getSpeed: function() {
62 | return new Error('抽象方法不能调用');
63 | }
64 | };
65 |
66 | // 宝马汽车子类
67 | var BMW = function(price, speed) {
68 | this.price = price;
69 | this.speed = speed;
70 | };
71 |
72 | VehicleFactory(BMW, 'Car');
73 |
74 | BMW.prototype.getPrice = function() {
75 | return this.price;
76 | };
77 | BMW.prototype.getSpeed = function() {
78 | return this.speed;
79 | };
80 |
81 | var a = new BMW(100, 2);
82 |
83 | console.log(a.getPrice());
84 | console.log(a.type);
--------------------------------------------------------------------------------
/chapter15/1.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // 背景:分页新闻功能
4 |
5 | // 享元对象
6 | var Flyweight = (function() {
7 | // 已创建的元素
8 | var created = [];
9 |
10 | /*
11 | * 创建一个新闻包装容器
12 | * 根据我自己对享元模式的理解,享元模式的精髓就在于『创建对象的同时,缓存一份对象,日后直接对缓存的对象做操作』
13 | */
14 | function create() {
15 | var dom = document.createElement('div');
16 | // 讲容器插入新闻列表容器中
17 | document.getElementById('container').appendChild(dom);
18 | // 缓存新创建的元素
19 | created.push(dom);
20 | // 返回创建的新元素
21 | return dom;
22 | }
23 |
24 | return {
25 | // 获取创建新闻元素方法
26 | getDiv: function() {
27 | // 如果已创建的元素小于当前页元素总个数,则创建
28 | if (created.length < 5) {
29 | return create();
30 | } else {
31 | // 获取第一个元素并插入到最后面
32 | var div = created.shift();
33 | created.push(div);
34 | return div;
35 | }
36 | }
37 | };
38 | })();
39 |
40 |
41 | // 实现需求
42 | var paper = 0;
43 | var num = 5;
44 | var article = ['这是第一条新闻','这是第二条新闻','这是第三条新闻','这是第四条新闻','这是第五条新闻','这是第六条新闻'];
45 | var len = article.length;
46 |
47 | // 添加五条新闻
48 | for (var i = 0; i < 5; i++) {
49 | if (article[i]) {
50 | // 通过享元类获取创建的元素并写入新闻内容
51 | Flyweight.getDiv().innerHTML = article[i];
52 | }
53 | }
54 |
55 | // 下一页
56 | document.getElementById('next').onclick = function() {
57 | // 如果新闻内容不足5条则返回
58 | if(article.length < 5) return;
59 |
60 | var n = ++paper * num % len;
61 |
62 | // 插入5条新闻
63 | for (var j = 0; j < 5; j++) {
64 | // 如果存在第n+j条则插入
65 | if (article[n + j]) {
66 | Flyweight.getDiv().innerHTML = article[n + j];
67 | } else if(article[n + j - len]) {
68 | // 否则插入起始位置第n + j - len 条
69 | Flyweight.getDiv().innerHTML = article[n + j - len];
70 | } else {
71 | // 如果都不存在则插入空字符串
72 | Flyweight.getDiv().innerHTML = '';
73 | }
74 | }
75 | };
--------------------------------------------------------------------------------
/chapter26/1.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // 个人觉得这章讲的并不是设计模式。
4 |
5 | // 获取兄弟元素名称
6 | function getSublingName(node) {
7 | if (node.previousSibling) {
8 | var name = '';
9 | var count = 1;
10 | var nodeName = node.nodeName;
11 | var sibling = node.previousSibling;
12 |
13 | while (sibling) {
14 | // 如果节点为元素 并且 节点类型与前一个兄弟类型相同,并且前一个兄弟元素名称存在
15 | if (sibling.nodeType == 1 && sibling.nodeType === node.nodeType && sibling.nodeName) {
16 | if (nodeName == sibling.nodeName) {
17 | name += ++count;
18 | } else {
19 | // 重置相同紧邻节点名称节点个数
20 | count = 1;
21 | name += '|' + sibling.nodeName.toUpperCase();
22 | }
23 | }
24 |
25 | sibling = sibling.previousSibling;
26 | }
27 |
28 | return name;
29 | } else {
30 | return '';
31 | }
32 | }
33 |
34 | // XPath 解释器
35 | var Interpreter = (function() {
36 | return function(node, wrap) {
37 | var path = [];
38 | wrap = wrap || document;
39 |
40 | // 如果当前(目标)节点等于容器节点
41 | if (node === wrap) {
42 | if (wrap.nodeType === 1) {
43 | path.push( wrap.nodeName.toUpperCase() );
44 | }
45 |
46 | return path;
47 | }
48 |
49 | if (node.parentNode !== wrap) {
50 | path = Interpreter(node.parentNode, wrap);
51 | } else {
52 | if (wrap.nodeType == 1) {
53 | path.push( wrap.nodeName.toUpperCase() );
54 | }
55 | }
56 |
57 | var sublingsNames = getSublingName(node);
58 |
59 | if (node.nodeType == 1) {
60 | path.push(node.nodeName.toUpperCase() + sublingsNames);
61 | }
62 |
63 | return path;
64 | }
65 | })();
66 |
67 |
68 |
69 | var path = Interpreter(document.getElementById('test'));
70 | console.log(path.join('>')); // HTML>BODY|HEAD>P2
71 |
72 | // 测试html
73 | // 222
74 |
75 |
--------------------------------------------------------------------------------
/chapter35/1.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var F = F || {};
4 |
5 | F.define = function(str, fn) {
6 | var parts = str.split('.');
7 | var old = this;
8 | var parent = this;
9 | var i = 0;
10 |
11 | if (parts[0] === 'F') {
12 | parts = parts.slice(1);
13 | }
14 |
15 | // 如果是框架内部方法,return
16 | if (parts[0] === 'define' || parts[0] === 'module') {
17 | return;
18 | }
19 |
20 | for (var len = parts.length; i < len; i++) {
21 | if (typeof parent[parts[i]] === 'undefined') {
22 | parent[parts[i]] = {};
23 | }
24 |
25 | old = parent;
26 |
27 | parent = parent[parts[i]];
28 | }
29 |
30 | if (fn) {
31 | // 此时i等于parts.length故减一
32 | old[parts[--i]] = fn();
33 | }
34 |
35 | return this;
36 | };
37 |
38 | F.module = function() {
39 | var args = Array.prototype.slice.call(arguments);
40 | var fn = args.pop();
41 | var parts = args[0] && args[0] instanceof Array ? args[0] : args;
42 | var modules = [];
43 | var modIDs = '';
44 | var i = 0;
45 | var ilen = parts.length;
46 |
47 | while (i < ilen) {
48 | if (typeof parts[i] === 'string') {
49 | var parent = this;
50 | modIDs = parts[i].replace(/^F\./, '').split('.');
51 | for (var j = 0; j < modIDs.length; j++) {
52 | parent = parent[modIDs[j]] || false;
53 | }
54 | modules.push(parent);
55 | } else {
56 | modules.push(parent[i]);
57 | }
58 |
59 | i++
60 | }
61 |
62 | fn.apply(null, modules);
63 | };
64 |
65 | F.define('string', function() {
66 | return {
67 | trim: function(str) {
68 | return str.replace(/^\s+|\s+$/g, '');
69 | }
70 | }
71 | });
72 |
73 | F.module('string.trim', function(trim) {
74 | console.log( trim(' 测试一下 ') );
75 | });
76 |
77 | F.module(['string'], function(string) {
78 | console.log( string.trim(' 测试一下2 ') );
79 | });
80 |
81 | /*
82 | * 总结
83 | *
84 | * define方法就是以第一个参数为key,第二个参数为value在F对象上添加一个方法,当然中间会有一个判断神马的
85 | *
86 | * module方法就是以第一个参数为key读取F对象上的方法push到数组中,用参数统一传给第二个参数
87 | *
88 | */
--------------------------------------------------------------------------------
/chapter6/1.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var Human = function(param) {
4 |
5 | // 技能
6 | this.skill = param && param.skill || '保密';
7 |
8 | // 兴趣爱好
9 | this.hobby = param && param.hobby || '保密';
10 | };
11 |
12 | Human.prototype = {
13 | getSkill: function() {
14 | return this.skill;
15 | },
16 | getHobby: function() {
17 | return this.hobby;
18 | }
19 | };
20 |
21 | // 实例化姓名类
22 | var Named = function(name) {
23 | var that = this;
24 |
25 | // 构造器
26 | // 构造函数解析姓名的姓与名
27 | (function(name, that) {
28 | that.wholeName = name;
29 |
30 | if (name.indexOf(' ') > -1) {
31 | that.firstName = name.slice(0, name.indexOf(' '));
32 | that.secondName = name.slice(name.indexOf(' '));
33 | }
34 | })(name, that)
35 | };
36 |
37 | // 实例化职位类
38 | var Work = function(work) {
39 | var that = this;
40 |
41 | // 构造器
42 | // 构造函数中通过传入的职位特征来设置相应职位以及描述
43 | (function(work, that) {
44 | switch(work) {
45 | case 'code':
46 | that.work = '工程师';
47 | that.workDescript = '每天沉醉于编程';
48 | break;
49 | case 'UI':
50 | case 'UE':
51 | that.work = '设计师';
52 | that.workDescript = '设计更似一种艺术';
53 | break;
54 | case 'teach':
55 | that.work = '教师';
56 | that.workDescript = '分享也是一种快乐';
57 | break;
58 | default:
59 | that.work = work;
60 | that.workDescript = '对不起,我们还不清楚您所选择职位的相关描述';
61 | }
62 | })(work, that);
63 | };
64 |
65 | // 更换期望的职位
66 | Work.prototype.changeWork = function(work) {
67 | this.work = work;
68 | }
69 |
70 | // 添加对职位的描述
71 | Work.prototype.changeDescript = function(des) {
72 | this.workDescript = des;
73 | };
74 |
75 |
76 | /**
77 | * 应聘者建造者
78 | *
79 | * @param name 姓名(全名)
80 | * @param work 期望职位
81 | */
82 | var Person = function(name, work) {
83 | // 创建应聘者缓存对象
84 | var _person = new Human();
85 |
86 | // 创建应聘者姓名解析对象
87 | _person.name = new Named(name);
88 |
89 | // 创建应聘者期望职位
90 | _person.work = new Work(work);
91 |
92 | return _person;
93 | };
94 |
95 | var person = new Person('xiao ming', 'code');
96 | console.log(person)
--------------------------------------------------------------------------------
/chapter36/1.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | (function (F) {
4 | var moduleCache = {};
5 | var getUrl = function (moduleName) {
6 | return String(moduleName).replace(/\.js$/g, '') + '.js';
7 | };
8 | var loadScript = function (src) {
9 | var _script = document.createElement('script');
10 | _script.type = 'text/javascript';
11 | _script.charset = 'UTF-8';
12 | _script.async = true;
13 | _script.src = src;
14 | document.getElementsByTagName('head')[0].appendChild(_script);
15 | };
16 |
17 | var loadModule = function (moduleName, cb) {
18 | var _module;
19 |
20 | if (moduleCache[moduleName]) {
21 | _module = moduleCache[moduleName];
22 |
23 | if (_module.status === 'loaded') {
24 | setTimeout(cb(_module.exports), 0);
25 | } else {
26 | _module.onload.push(cb);
27 | }
28 | } else {
29 | moduleCache[moduleName] = {
30 | moduleName: moduleName,
31 | status: 'loading',
32 | exports: null,
33 | onload: [cb]
34 | };
35 |
36 | loadScript(getUrl(moduleName));
37 | }
38 | };
39 |
40 | var setModule = function (moduleName, params, cb) {
41 | var _module, fn;
42 |
43 | if (moduleCache[moduleName]) {
44 | _module = moduleCache[moduleName];
45 | _module.status = 'loaded';
46 | _module.exports = cb ? cb.apply(_module, params) : null;
47 |
48 | while (fn = _module.onload.shift()) {
49 | fn(_module.exports);
50 | }
51 | } else {
52 | cb && cb.apply(null, params);
53 | }
54 | };
55 |
56 | F.module = function () {
57 | var args = Array.prototype.slice.call(arguments);
58 | var callback = args.pop();
59 | var deps = (args.length && args[args.length - 1] instanceof Array) ? args.pop() : [];
60 | var url = args.length ? args.pop() : null;
61 | var params = [];
62 | var depsCount = 0;
63 | var len;
64 |
65 | if (len = deps.length) {
66 | for (var i = 0; i < len; i++) {
67 | (function (i) {
68 | depsCount++;
69 | loadModule(deps[i], function (mod) {
70 | params[i] = mod;
71 | depsCount--;
72 |
73 | if (depsCount === 0) {
74 | setModule(url, params, callback);
75 | }
76 | });
77 | })(i);
78 | }
79 | } else {
80 | setModule(url, [], callback);
81 | }
82 | };
83 |
84 |
85 | })((function () {
86 | return window.F = {};
87 | })());
--------------------------------------------------------------------------------
/chapter21/1.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /*
4 | * 实现模块
5 | */
6 | var ViewCommand = (function() {
7 |
8 | // 模板
9 | var tpl = {
10 | product: [
11 | '',
12 | '

',
13 | '
{#text#}
',
14 | '
'
15 | ].join(''),
16 |
17 | title: [
18 | '',
19 | '
',
20 | '
{#title#}
',
21 | '
{#tips#}
',
22 | '
',
23 | '
'
24 | ].join(''),
25 | };
26 |
27 | var html = '';
28 |
29 | // 替换数据
30 | function formatString(str, obj) {
31 | return str.replace(/\{#(\w+)#\}/g, function(match, key) {
32 | return obj[key];
33 | });
34 | }
35 |
36 | // 方法集合
37 | var Action = {
38 | create: function(data, view) {
39 | // 如果是数字则把数组中的每一项加进html中
40 | if (Object.prototype.toString.call(data) === '[object Array]') {
41 | for (var i = 0; i < data.length; i++) {
42 | html += formatString(tpl[view], data[i]);
43 | }
44 | } else {
45 | html += formatString(tpl[view], data);
46 | }
47 | },
48 | display: function(container, data, view) {
49 | // 如果有数据,根据数据创建视图
50 | if (data) this.create(data, view);
51 |
52 | document.getElementById(container).innerHTML = html;
53 | html = '';
54 | }
55 | };
56 |
57 | return function excute(command) {
58 | command.param = Object.prototype.toString.call(command.param) === '[object Array]' ? command.param : [command.param];
59 | Action[command.cd].apply(Action, command.param);
60 | }
61 | })();
62 |
63 |
64 | /*
65 | * 测试
66 | */
67 |
68 | // 产品展示数据
69 | var productData = [{
70 | src: 'command/02.jpg',
71 | text: '绽放的桃花'
72 | },{
73 | src: 'command/03.jpg',
74 | text: '阳光下的温馨'
75 | },{
76 | src: 'command/04.jpg',
77 | text: '镜头前的绿色'
78 | }];
79 |
80 | // 模块标题数据
81 | var titleData = {
82 | title: '夏日里的一片温馨',
83 | tips: '暖暖的温情带给人们家的感受'
84 | };
85 |
86 | ViewCommand({
87 | cd: 'display',
88 | param: ['title', titleData, 'title']
89 | });
90 |
91 | ViewCommand({
92 | cd: 'create',
93 | param: [{
94 | src: 'command/01.jpg',
95 | text: '迎着朝阳的野菊花'
96 | }, 'product']
97 | });
98 |
99 | ViewCommand({
100 | cd: 'display',
101 | param: ['product', productData, 'product']
102 | });
103 |
104 |
105 | /*
106 | * 测试HTML
107 | *
108 | *
109 | *
110 | */
111 |
--------------------------------------------------------------------------------
/chapter34/1.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var Waiter = function () {
4 | var dfd = [];
5 | var doneArr = [];
6 | var failArr = [];
7 | var slice = Array.prototype.slice;
8 | var self = this;
9 |
10 | var Primise = function () {
11 | // 监控对象是否解决成功状态
12 | this.resolved = false;
13 | // 监控对象是否解决失败状态
14 | this.rejected = false;
15 | };
16 |
17 | Primise.prototype = {
18 | resolve: function () {
19 | this.resolved = true;
20 |
21 | if (!dfd.length) return;
22 |
23 | for (var i = dfd.length - 1; i >= 0; i--) {
24 | // 如果有任意一个监控对象没有被解决或者解决失败则返回
25 | if (dfd[i] && !dfd[i].resolved || dfd[i].rejected) return;
26 | // 清除监控对象
27 | dfd.splice(i, 1);
28 | };
29 |
30 | _exec(doneArr);
31 | },
32 |
33 | reject: function () {
34 | this.rejected = true;
35 |
36 | if (!dfd.length) return;
37 |
38 | dfd.splice(0);
39 |
40 | _exec(failArr);
41 | }
42 | };
43 |
44 | self.Deferred = function () {
45 | return new Primise();
46 | };
47 |
48 | function _exec(arr) {
49 | for (var i = 0; i < arr.length; i++) {
50 | try {
51 | arr[i] && arr[i]();
52 | } catch(e) {}
53 | }
54 | }
55 |
56 | /*
57 | * 监控异步方法
58 | *
59 | * @param 监控对象
60 | */
61 | self.when = function () {
62 | dfd = slice.call(arguments);
63 |
64 | for (var i = dfd.length - 1; i >= 0; i--) {
65 | if (!dfd[i] || dfd[i].resolved || dfd[i].rejected || !dfd[i] instanceof Primise) {
66 | dfd.splice(i, 1);
67 | }
68 | };
69 |
70 | return self;
71 | };
72 |
73 | // 添加成功回调函数的方法
74 | self.done = function () {
75 | doneArr = doneArr.concat(slice.call(arguments));
76 | return self;
77 | };
78 |
79 | // 添加失败回调函数的方法
80 | self.fail = function () {
81 | failArr = failArr.concat(slice.call(arguments));
82 | return self;
83 | };
84 | };
85 |
86 |
87 | // 测试
88 | var waiter = new Waiter();
89 |
90 | var first = (function() {
91 | var dtd = waiter.Deferred();
92 |
93 | setTimeout(function () {
94 | console.log('first finish');
95 | dtd.resolve();
96 | }, 5000);
97 |
98 | return dtd;
99 | })();
100 |
101 | var second = (function() {
102 | var dtd = waiter.Deferred();
103 |
104 | setTimeout(function () {
105 | console.log('second finish');
106 | dtd.resolve();
107 | }, 3000);
108 |
109 | return dtd;
110 | })();
111 |
112 | waiter.when(first, second).done(function () {
113 | console.log('success');
114 | }, function () {
115 | console.log('success again');
116 | }).fail(function () {
117 | console.log('fail');
118 | });
--------------------------------------------------------------------------------
/chapter27/1.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var A = function(selector) {
4 | return new A.fn.init(selector);
5 | };
6 |
7 | A.fn = A.prototype = {
8 |
9 | constructor: A,
10 |
11 | // 一些浏览器引擎在判断对象是否是数组的时候,不仅仅判断有没有length属性,是否通过‘[索引值]’方式访问元素,还会判断是否具有数组方法来确定是否要用数组的形式展现
12 | // 所以添加几个数组常用的方法增强数组特性
13 | push: Array.prototype.push,
14 | sort: Array.prototype.sort,
15 | splice: Array.prototype.splice,
16 |
17 | init: function(selector) {
18 | this[0] = document.getElementById(selector);
19 | this.length = 1;
20 | return this;
21 | },
22 |
23 | size: function() {
24 | return this.length;
25 | }
26 | }
27 |
28 | A.fn.init.prototype = A.fn;
29 |
30 | // 对象扩展
31 | A.extend = A.fn.extend = function() {
32 | // 扩展对象从第二个参数算起
33 | var i = 1;
34 |
35 | // 获取参数长度
36 | var len = arguments.length;
37 |
38 | // 第一个参数为源对象
39 | var target = arguments[0];
40 |
41 | if (i == len) {
42 | // 源对象等于当前对象
43 | target = this;
44 |
45 | // i从0计数
46 | i--;
47 |
48 | for (; i < len; i++) {
49 | for (var j in arguments[i]) {
50 | target[j] = arguments[i][j];
51 | }
52 | }
53 |
54 | return target;
55 | }
56 | };
57 |
58 | A.fn.extend({
59 | // 添加事件
60 | on: (function() {
61 | return function(type, fn) {
62 | if (document.addEventListener) {
63 | for (var i = 0; i < this.length; i++) {
64 | this[i].addEventListener(type, fn, false);
65 | }
66 | } else if (document.attachEvent) {
67 | for (var i = 0; i < this.length; i++) {
68 | this[i].attachEvent('on' + type, fn);
69 | }
70 | } else {
71 | for (var i = 0; i < this.length; i++) {
72 | this[i]['on' + type] = fn;
73 | }
74 | }
75 | return this;
76 | }
77 | })(),
78 |
79 | // 设置属性
80 | attr: function() {
81 | var arg = arguments;
82 | var len = arg.length;
83 |
84 | if (this.length < 1) return this;
85 |
86 | if (len === 1) {
87 | if (typeof arg[0] === 'string') {
88 | return this[0].getAttribute(arg[0]);
89 | }
90 |
91 | if (typeof arg[0] === 'object') {
92 | for (var i in arg[0]) {
93 | for (var j = 0; j < this.length; j++) {
94 | return this[j].setAttribute(i, arg[0][i]);
95 | }
96 | }
97 | }
98 | } else if (len === 2) {
99 | for (var j = 0; j < this.length; j++) {
100 | this[j].setAttribute(arg[0], arg[1]);
101 | }
102 | }
103 |
104 | return this;
105 | }
106 | })
107 |
108 |
109 | A('test').attr('class', 'demo').on('click', function() {
110 | console.log('clicked');
111 | });
112 |
113 | // 测试html
114 |
115 | /*
116 | test
117 | */
--------------------------------------------------------------------------------
/chapter17/3.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /*
4 | * 观察者模式
5 | *
6 | * 将观察者放在闭包中,当页面加载就立即执行
7 | */
8 | var Observer = (function() {
9 | // 防止消息队列暴漏而被篡改,故将消息容器作为静态私有变量保存。
10 | var __message = {};
11 |
12 | return {
13 | // 注册信息接口(订阅)
14 | subscribe: function(type, fn) {
15 | // 如果消息不存在则创建一个消息类型
16 | if (!__message[type]) {
17 | __message[type] = [fn];
18 | } else {
19 | // 将动作方法推送到消息对应的动作执行序列中
20 | __message[type].push(fn);
21 | }
22 | },
23 |
24 | // 发布消息接口(取消订阅)
25 | unsubscribe: function(type, fn) {
26 | if (!__message[type] || Object.prototype.toString.call(__message[type]) !== '[object Array]') return;
27 |
28 | for (var i = __message[type].length - 1; i >= 0; i--) {
29 | __message[type][i] === fn && __message[type].splice(i, 1);
30 | };
31 | },
32 |
33 | // 移除信息接口(移除信息接口)
34 | publish: function(type, args) {
35 | if (!__message[type]) return;
36 |
37 | // 定义消息信息
38 | var events = {
39 | type: type,
40 | args: args
41 | };
42 |
43 | // 执行注册的消息所对应的所有动作序列
44 | for (var i = 0; i < __message[type].length; i++) {
45 | __message[type][i].call(this, events);
46 | }
47 | }
48 | }
49 | })();
50 |
51 |
52 | // 学生类
53 | var Student = function(result) {
54 | var self = this;
55 |
56 | // 学生回答结果
57 | self.result = result;
58 |
59 | // 学生回答问题动作
60 | self.say = function() {
61 | console.log(self.result);
62 | };
63 | };
64 |
65 | // 回答问题方法
66 | Student.prototype.answer = function(question) {
67 | // 注册参数问题
68 | Observer.subscribe(question, this.say);
69 | };
70 |
71 | Student.prototype.sleep = function(question) {
72 | Observer.unsubscribe(question, this.say);
73 | };
74 |
75 |
76 | // 教师类
77 | var Teacher = function() {};
78 | Teacher.prototype.ask = function(question) {
79 | console.log('问题是:' + question);
80 | // 发布提问消息
81 | Observer.publish(question);
82 | };
83 |
84 |
85 | // 模拟听课的学生
86 | var student1 = new Student('学生1回答问题');
87 | var student2 = new Student('学生2回答问题');
88 | var student3 = new Student('学生3回答问题');
89 |
90 | // 注册一下哪位学生回答什么问题
91 | student1.answer('什么是设计模式');
92 | student1.answer('简述观察者模式');
93 | student2.answer('什么是设计模式');
94 | student3.answer('什么是设计模式');
95 | student3.answer('简述观察者模式');
96 |
97 | // 后来第三位同学睡着了。。
98 | student3.sleep('简述观察者模式');
99 |
100 |
101 | var teacher = new Teacher();
102 |
103 | // 提问
104 | teacher.ask('什么是设计模式');
105 | teacher.ask('简述观察者模式');
106 |
107 | // 最后,两个问题,第一个问题三名同学回答,第二个问题只有第一名同学回答。。。
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
--------------------------------------------------------------------------------
/chapter37/1.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var tplEngine = {
4 | /*
5 | * 获取模板
6 | *
7 | * @param str 模板容器ID或模板字符串
8 | * @return str 最终结果
9 | */
10 | getTpl: function(str) {
11 | var ele = (typeof module === 'object' && module.exports) ? false : document.getElementById(str);
12 |
13 | if (ele) {
14 | var html = /textarea|input/i.test(ele.nodeName) ? ele.value : ele.innerHTML;
15 | return this.compileTpl(html);
16 | } else {
17 | return this.compileTpl(str);
18 | }
19 | },
20 |
21 | /*
22 | * 处理模板
23 | */
24 | dealTpl: function(str) {
25 | var _left = '{%';
26 | var _right = '%}';
27 |
28 | return String(str)
29 |
30 | // 转义
31 | .replace(/</g, '<')
32 | .replace(/>/g, '>')
33 |
34 | // 过滤回车,制表符,回车符
35 | .replace(/[\r|\t|\n]/g, '')
36 |
37 | // 替换内容
38 | .replace(new RegExp(_left+'=(.*?)'+_right, 'g'), "',typeof($1)==='undefined'?'':$1,'")
39 |
40 | // 替换左分隔符
41 | .replace(new RegExp(_left, 'g'), "');")
42 |
43 | // 替换右分隔符
44 | .replace(new RegExp(_right, 'g'), "template_array.push('");
45 | },
46 |
47 | /*
48 | * 编译模板
49 | */
50 | compileTpl: function(str) {
51 | var fnBody = [
52 | "var template_array=[];\n",
53 | "var fn=(function(data){\n",
54 | "var template_key='';\n",
55 | "for(key in data){\n",
56 | "template_key+=('var '+key+'=data[\"'+key+'\"];');\n",
57 | "}\n",
58 | "eval(template_key);\n",
59 | "template_array.push('"+this.dealTpl(str)+"');\n",
60 | "template_key=null;\n",
61 | "})(templateData);\n",
62 | "fn=null;\n",
63 | "return template_array.join('');"
64 | ].join('');
65 |
66 | return new Function('templateData', fnBody);
67 | }
68 | };
69 |
70 | /*
71 | * 模板引擎
72 | *
73 | * @param str 模板容器ID或模板字符串
74 | * @param data 数据
75 | *
76 | * @return 处理好的html
77 | */
78 | function template(str, data) {
79 | if (Object.prototype.toString.call(data) === '[object Array]') {
80 | var html = '';
81 |
82 | for (var i = 0; i < data.length; i++) {
83 | html += tplEngine.getTpl(str)(data[i]);
84 | }
85 |
86 | return html;
87 | } else {
88 | return tplEngine.getTpl(str)(data);
89 | }
90 | }
91 |
92 | // test
93 |
94 | var data = {
95 | tagCloud: [
96 | {selected: true, title: '这是一本设计模式书', text: '设计模式'},
97 | {selected: false, title: '这是一本Nodejs书', text: 'Node.js'},
98 | {selected: false, title: '这是一本javascript书', text: 'javascript'}
99 | ]
100 | };
101 |
102 | var str = [
103 | '',
104 | '{% for (var i = 0; i < tagCloud.length; i++){ %}',
105 | '
{%= tagCloud[i].text %}',
106 | '{% } %}',
107 | '
'
108 | ].join('');
109 |
110 | var html = template(str, data);
111 | console.log(html);
112 |
113 |
114 |
115 |
--------------------------------------------------------------------------------
/chapter17/2.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // 背景:评论+消息通知
4 |
5 | /*
6 | * 观察者模式
7 | *
8 | * 将观察者放在闭包中,当页面加载就立即执行
9 | */
10 | var Observer = (function() {
11 | // 防止消息队列暴漏而被篡改,故将消息容器作为静态私有变量保存。
12 | var __message = {};
13 |
14 | return {
15 | // 注册信息接口(订阅)
16 | subscribe: function(type, fn) {
17 | // 如果消息不存在则创建一个消息类型
18 | if (!__message[type]) {
19 | __message[type] = [fn];
20 | } else {
21 | // 将动作方法推送到消息对应的动作执行序列中
22 | __message[type].push(fn);
23 | }
24 | },
25 |
26 | // 发布消息接口(取消订阅)
27 | unsubscribe: function(type, fn) {
28 | if (!__message[type] || Object.prototype.toString.call(__message[type]) !== '[object Array]') return;
29 |
30 | for (var i = __message[type].length - 1; i >= 0; i--) {
31 | __message[type][i] === fn && __message[type].splice(i, 1);
32 | };
33 | },
34 |
35 | // 移除信息接口(移除信息接口)
36 | publish: function(type, args) {
37 | if (!__message[type]) return;
38 |
39 | // 定义消息信息
40 | var events = {
41 | type: type,
42 | args: args
43 | };
44 |
45 | // 执行注册的消息所对应的所有动作序列
46 | for (var i = 0; i < __message[type].length; i++) {
47 | __message[type][i].call(this, events);
48 | }
49 | }
50 | }
51 | })();
52 |
53 | // 外观模式
54 | function $(id) {
55 | return document.getElementById(id);
56 | }
57 |
58 | // 工程师A
59 | (function() {
60 |
61 | // 新增一条消息
62 | function addMsgItem(e) {
63 | var text = e.args.text;
64 | var ul = $('msg');
65 | var li = document.createElement('li');
66 | var span = document.createElement('span');
67 |
68 | li.innerHTML = text;
69 |
70 | // 关闭按钮
71 | span.onclick = function() {
72 | ul.removeChild(li);
73 |
74 | Observer.publish('removeCommentMessage', {
75 | num: -1
76 | });
77 | };
78 |
79 | ul.appendChild(span);
80 | ul.appendChild(li);
81 | }
82 |
83 | Observer.subscribe('addCommentMessage', addMsgItem);
84 | })();
85 |
86 | // 工程师B
87 | (function() {
88 |
89 | // 修改用户消息数目
90 | function changeMsgNum(e) {
91 | var num = e.args.num;
92 | $('msg_num').innerHTML = parseInt($('msg_num').innerHTML || 0) + 1;
93 | }
94 |
95 | // 注册添加评论信息
96 | Observer.subscribe('addCommentMessage', changeMsgNum);
97 | Observer.subscribe('removeCommentMessage', changeMsgNum);
98 |
99 | })();
100 |
101 |
102 | // 工程师C
103 | (function() {
104 |
105 | // 用户点击提交按钮
106 | $('user_submit').onclick = function() {
107 | var text = $('user_input');
108 |
109 | if (!text.value) return;
110 |
111 | Observer.publish('addCommentMessage', {
112 | text: text.value,
113 | num: 1
114 | });
115 |
116 | text.value = '';
117 | };
118 |
119 | })();
120 |
121 | /*
122 | * 测试HTML
123 | *
124 | *
125 | *
126 | *
127 | *
128 | */
--------------------------------------------------------------------------------
/chapter25/1.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // 背景:页面中有好多焦点图,每一种都要重写一遍元素循环,所以需要建立一个基类,然后让不同种类的焦点图(轮播,淡入淡出)继承基类,此外,迭代器模式比较适合解决重复循环迭代的问题
4 |
5 |
6 | // 迭代器
7 | var Iterator = function(items, container) {
8 | var container = container && document.getElementById(container) || document;
9 | var items = container.getElementsByTagName(items);
10 |
11 | var length = items.length;
12 |
13 | // 当前索引
14 | var index = 0;
15 |
16 | var splice = Array.prototype.splice;
17 |
18 | return {
19 | /*
20 | * 获取第一个元素
21 | */
22 | first: function() {
23 | index = 0;
24 | return items[index];
25 | },
26 |
27 | /*
28 | * 获取最后一个元素
29 | */
30 | second: function() {
31 | index = length - 1;
32 | return items[index];
33 | },
34 |
35 | /*
36 | * 获取前一个元素
37 | */
38 | prev: function() {
39 | if (--index > 0) {
40 | return items[index];
41 | } else {
42 | index = 0;
43 | return items[index];
44 | }
45 | },
46 |
47 | /*
48 | * 获取后一个元素
49 | */
50 | next: function() {
51 | if (++index < length) {
52 | return items[index];
53 | } else {
54 | index = length - 1;
55 | return items[index];
56 | }
57 | },
58 |
59 | /*
60 | * 获取某一个元素
61 | */
62 | get: function(num) {
63 | index = num >= 0 ? num % length : num % length + length;
64 | return items[index];
65 | },
66 |
67 | /*
68 | * 对每一个元素执行某一个方法
69 | */
70 | dealEach: function(fn) {
71 | var args = splice.call(arguments, 1);
72 |
73 | for (var i = 0; i < length; i++) {
74 | fn.apply(items[i], args);
75 | }
76 | },
77 |
78 | /*
79 | * 对某一个元素执行某一个方法
80 | */
81 | dealItem: function(num, fn) {
82 | var args = splice.call(arguments, 2);
83 | // 通过this.get方法设置index索引值
84 | fn.apply(this.get(num), args);
85 | },
86 |
87 | /*
88 | * 排他方式处理某一个元素
89 | */
90 | exclusive: function(num, allFn, numFn) {
91 | // 对所有元素执行回调函数
92 | this.dealEach(allFn);
93 |
94 | // 如果num为数组
95 | if (Object.prototype.toString.call(num) === '[object Array]') {
96 | for (var i = 0; i < num.length; i++) {
97 | this.dealItem(num[i], numFn);
98 | }
99 | } else {
100 | this.dealItem(num, numFn);
101 | }
102 | }
103 | };
104 | };
105 |
106 | var test = Iterator('li', 'container');
107 |
108 | console.log(test.first());
109 | console.log(test.prev());
110 | console.log(test.next());
111 | console.log(test.get(2000));
112 |
113 | // 处理所有元素
114 | test.dealEach(function(text, color) {
115 | this.innerHTML = text;
116 | this.style.background = color;
117 | }, 'test', 'pink');
118 |
119 | // 排他思想处理第3个与第4个元素
120 | test.exclusive([2, 3], function() {
121 | this.innerHTML = '被排除的';
122 | this.style.background = 'green';
123 | }, function() {
124 | this.innerHTML = '选中的';
125 | this.style.background = 'red';
126 | });
127 |
128 | // 测试HTML
129 |
130 | /*
131 |
132 |
133 |
134 |
135 |
*/
--------------------------------------------------------------------------------
/chapter23/2.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // 中介者对象
4 | var Mediator = (function() {
5 | // 消息对象
6 | var _msg = {};
7 |
8 | return {
9 | subscribe: function(type, action) {
10 | if (_msg[type]) {
11 | _msg[type].push(action);
12 | } else {
13 | _msg[type] = [];
14 | _msg[type].push(action);
15 | }
16 | },
17 |
18 | send: function(type) {
19 | if (_msg[type]) {
20 | for (var i = 0; i < _msg[type].length; i++) {
21 | _msg[type][i] && _msg[type][i]();
22 | }
23 | }
24 | }
25 | };
26 | })();
27 |
28 | /*
29 | * 显示隐藏导航小组件
30 | *
31 | * mod 模块
32 | * tag 标签
33 | * showOrHide 显示还是隐藏
34 | */
35 | var showHideNavWidget = function(mod, tag, showOrHide) {
36 | var mod = document.getElementById(mod);
37 | var tag = mod.getElementsByTagName(tag);
38 | var showOrHide = (!showOrHide || showOrHide === 'hide') ? 'hidden' : 'visible';
39 |
40 | // 占位隐藏这些标签
41 | for (var i = 0; i < tag.length; i ++) {
42 | tag[i].style.visibility = showOrHide;
43 | }
44 | };
45 |
46 | /*
47 | * 用户手册导航模块
48 | */
49 | (function() {
50 | // 订阅 隐藏用户收藏导航信息提醒消息
51 | Mediator.subscribe('hideAllNavNum', function() {
52 | showHideNavWidget('collection_nav', 'b', false);
53 | });
54 |
55 | // 订阅 显示用户收藏导航信息提醒消息
56 | Mediator.subscribe('showAllNavNum', function() {
57 | showHideNavWidget('collection_nav', 'b', true);
58 | });
59 |
60 | // 订阅 隐藏用户收藏导航网址消息
61 | Mediator.subscribe('hideAllNavUrl', function() {
62 | showHideNavWidget('collection_nav', 'span', false);
63 | });
64 |
65 | // 订阅 显示用户收藏导航网址消息
66 | Mediator.subscribe('showAllNavUrl', function() {
67 | showHideNavWidget('collection_nav', 'span', true);
68 | });
69 | })();
70 |
71 | /*
72 | * 推荐用户导航
73 | */
74 | (function() {
75 | // 订阅 隐藏推荐用户导航消息提醒消息
76 | Mediator.subscribe('hideAllNavNum', function() {
77 | showHideNavWidget('recommend_nav', 'b', false);
78 | });
79 |
80 | // 订阅 显示推荐用户导航消息提醒消息
81 | Mediator.subscribe('showAllNavNum', function() {
82 | showHideNavWidget('recommend_nav', 'b', true);
83 | });
84 | })();
85 |
86 | /*
87 | * 最近常用导航
88 | */
89 | (function() {
90 | // 订阅 隐藏最近常用导航网址消息
91 | Mediator.subscribe('hideAllNavUrl', function() {
92 | showHideNavWidget('recently_nav', 'span', 'hide');
93 | });
94 |
95 | // 订阅 显示最近常用导航网址消息
96 | Mediator.subscribe('showAllNavUrl', function() {
97 | showHideNavWidget('recently_nav', 'span', 'show');
98 | });
99 | })();
100 |
101 |
102 | /*
103 | * 设置层模块
104 | */
105 | (function() {
106 | // 消息提醒选框
107 | var hideNum = document.getElementById('hide_num');
108 | var hideUrl = document.getElementById('hide_url');
109 |
110 | // 消息提醒选框事件
111 | hideNum.onchange = function() {
112 | if (hideNum.checked) {
113 | Mediator.send('hideAllNavNum');
114 | } else {
115 | Mediator.send('showAllNavNum');
116 | }
117 | };
118 |
119 | // 网址选框事件
120 | hideUrl.onchange = function() {
121 | if (hideUrl.checked) {
122 | Mediator.send('hideAllNavUrl');
123 | } else {
124 | Mediator.send('showAllNavUrl');
125 | }
126 | };
127 | })();
128 |
129 |
130 |
131 | /*
132 | * 测试html
133 | *
134 |
135 | 网址
136 | url
137 |
138 |
139 | 用户手册导航模块
140 | b
141 | span
142 |
143 |
144 |
145 | 推荐用户导航
146 | b
147 |
148 |
149 |
150 | 最近常用导航
151 | span
152 |
153 | */
--------------------------------------------------------------------------------
/chapter29/1.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var BaseLocalStorage = function(preId, timeSign) {
4 | this.preId = preId;
5 | this.timeSign = timeSign || '|-|';
6 | };
7 |
8 | BaseLocalStorage.prototype = {
9 |
10 | // 操作状态
11 | status: {
12 | SUCCESS: 0,
13 | FAILURE: 1,
14 | OVERFLOW: 2,
15 | TIMEOUT: 3
16 | },
17 |
18 | // 保存本地存储链接
19 | storage: localStorage || window.localStorage,
20 |
21 | // 获取真实字段
22 | getKey: function(key) {
23 | return this.preId + key;
24 | },
25 |
26 | /*
27 | * 添加(修改)数据
28 | *
29 | * @param key 键
30 | * @param value 值
31 | * @param callback(status, key, value) 回调函数
32 | * @param time 过期时间
33 | */
34 | set: function(key, value, callback, time) {
35 | var status = this.status.SUCCESS;
36 | var key = this.getKey(key);
37 |
38 | try {
39 | time = new Date(time).getTime() || time.getTime();
40 | } catch(e) {
41 | time = new Date().getTime() + 1000 * 60 * 60 * 24 * 31;
42 | }
43 |
44 | try {
45 | // 添加数据
46 | this.storage.setItem(key, time + this.timeSign + value);
47 | } catch(e) {
48 | // 溢出失败,返回溢出状态
49 | status = this.status.OVERFLOW;
50 | }
51 |
52 | // 有回调函数则执行回调函数并传入参数操作状态,真实数据字段标识以及存储数据值
53 | callback && callback.call(this, status, key, value);
54 | },
55 |
56 | /*
57 | * 获取数据
58 | *
59 | * @param key 键
60 | * @param callback(status, value) 回调函数
61 | * @return {status: status, value: value}
62 | */
63 | get: function(key, callback) {
64 | var status = this.status.SUCCESS;
65 | var key = this.getKey(key);
66 | var value = null;
67 | var timeSignLen = this.timeSign.length;
68 | var self = this;
69 | var result = null;
70 |
71 | try {
72 | value = self.storage.getItem(key);
73 | } catch (e) {
74 | // 不支持localstorage的浏览器
75 | result = {
76 | status: self.status.FAILURE,
77 | value: null
78 | };
79 |
80 | callback && callback.call(self, result.status, result.value);
81 |
82 | return result;
83 | }
84 |
85 | if (value) {
86 | // 获取时间戳与存储数据之间的拼接符起始位置
87 | var index = value.indexOf(self.timeSign);
88 |
89 | // 获取时间戳
90 | var time = +value.slice(0, index);
91 |
92 | if (new Date(time).getTime() > new Date().getTime() || time == 0) {
93 | value = value.slice(index + timeSignLen);
94 | } else {
95 | // 如果时间为过期
96 | value = null;
97 | status = self.status.FAILURE;
98 | self.remove(key);
99 | }
100 | } else {
101 | status = self.status.FAILURE;
102 | }
103 |
104 | result = {
105 | status: status,
106 | value: value
107 | };
108 |
109 | callback && callback.call(self, result.status, result.value);
110 |
111 | return result;
112 | },
113 |
114 | // 删除数据
115 | remove: function (key, callback) {
116 | var status = this.status.FAILURE;
117 | var key = this.getKey(key);
118 | var value = null;
119 |
120 | try {
121 | value = this.storage.getItem(key);
122 | } catch (e) {}
123 |
124 | if (value) {
125 | try {
126 | this.storage.removeItem(key);
127 |
128 | status = this.status.SUCCESS;
129 | } catch(e) {}
130 | }
131 |
132 | callback && callback.call(this, status, status > 0 ? null : value.slice(value.indexOf(this.timeSign) + this.timeSign.length));
133 | }
134 | };
135 |
136 |
137 | var db = new BaseLocalStorage('bw_');
138 | db.set('test', 'hahaha', function(status, value) {
139 | console.log('set:', status, value);
140 | });
141 |
142 |
143 | db.get('test', function(status, value) {
144 | console.log('get:', status, value);
145 | });
146 |
147 | db.remove('test', function(status, value) {
148 | console.log('remove:', status, value);
149 | });
150 |
151 | db.remove('test', function(status, value) {
152 | console.log('remove', status, value);
153 | });
154 |
155 | db.get('test', function(status, value) {
156 | console.log('get:', status, value);
157 | });
--------------------------------------------------------------------------------
/chapter16/1.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // 我的理解是,先创建基础类,然后针对基础类做扩展
4 |
5 | // 背景:提示框
6 |
7 | /*
8 | * 模板类
9 | * 基础提示框
10 | *
11 | * @param data 渲染数据
12 | */
13 | var Alert = function(data) {
14 | if (!data) return;
15 |
16 | // 设置内容
17 | this.content = data.content;
18 |
19 | // 创建提示框面板
20 | this.panel = document.createElement('div');
21 | // 创建提示内容组件
22 | this.contentNode = document.createElement('p');
23 | // 创建确认按钮组件
24 | this.confirmBtn = document.createElement('span');
25 | // 创建关闭按钮组件
26 | this.closeBtn = document.createElement('b');
27 |
28 | // 为提示框面板添加class
29 | this.panel.className = 'alert';
30 | // 为确认按钮添加class
31 | this.confirmBtn.className = 'a-confirm';
32 | // 为关闭按钮添加class
33 | this.closeBtn.className = 'a-close';
34 |
35 | // 为确认按钮添加文案
36 | this.confirmBtn.innerHTML = data.confirm || '确认';
37 | // 为提示内容添加文本
38 | this.contentNode.innerHTML = data.content || '';
39 |
40 | // 点击确认按钮执行方法 如果 data 中有 success 方法则为 success 方法,否则为空函数
41 | this.success = data.success || function() {};
42 | // 点击关闭按钮执行方法
43 | this.fail = data.fail || function() {};
44 | };
45 |
46 | // 提示框原型方法
47 | Alert.prototype = {
48 |
49 | // 创建方法
50 | init: function() {
51 | // 生成提示框
52 | this.panel.appendChild(this.closeBtn);
53 | this.panel.appendChild(this.confirmBtn);
54 | this.panel.appendChild(this.contentNode);
55 |
56 | // 插入页面中
57 | document.body.appendChild(this.panel);
58 |
59 | // 绑定事件
60 | this.bindEvent();
61 |
62 | // 显示提示框
63 | this.show();
64 | },
65 |
66 | // 绑定事件
67 | bindEvent: function() {
68 | var self = this;
69 |
70 | this.closeBtn.onclick = function() {
71 | // 执行取消方法
72 | self.fail();
73 | // 隐藏弹层
74 | self.hide();
75 | };
76 |
77 | this.confirmBtn.onclick = function() {
78 | // 执行确认方法
79 | self.success();
80 |
81 | // 隐藏弹层
82 | self.hide();
83 | };
84 | },
85 |
86 | // 隐藏弹窗方法
87 | hide: function() {
88 | this.panel.style.display = 'none';
89 | },
90 |
91 | // 显示弹层方法
92 | show: function() {
93 | this.panel.style.display = 'block';
94 | }
95 | };
96 |
97 |
98 |
99 |
100 |
101 | /*
102 | * 右侧按钮提示框
103 | */
104 | var RightAlert = function(data) {
105 | // 继承基本提示框构造函数
106 | Alert.call(this, data);
107 |
108 | // 为确认按钮添加 right class设置位置居右
109 | this.confirmBtn.className = this.confirmBtn.className + ' right';
110 | };
111 |
112 | // 继承基本提示框方法
113 | RightAlert.prototype = new Alert();
114 |
115 |
116 | /*
117 | * 标题提示框
118 | */
119 | var TitleAlert = function(data) {
120 | // 继承基本提示框构造函数
121 | Alert.call(this, data);
122 |
123 | // 设置标题内容
124 | this.title = data.title;
125 |
126 | // 创建标题组件
127 | this.titleNode = document.createElement('h3');
128 |
129 | // 标题组件中写入标题内容
130 | this.titleNode.innerHTML = this.title;
131 | };
132 |
133 | // 继承原型
134 | TitleAlert.prototype = new Alert();
135 |
136 | // 对基本提示框创建方法扩展
137 | TitleAlert.prototype.init = function() {
138 | // 插入标题
139 | this.panel.insertBefore(this.titleNode, this.panel.firstChild);
140 |
141 | // 继承基本提示框init方法
142 | Alert.prototype.init.call(this);
143 | };
144 |
145 | /***** 继承类也可作为模板类 *****/
146 |
147 | /*
148 | * 带有取消按钮的弹出框
149 | */
150 | var CancelAlert = function(data) {
151 | // 继承标题提示框构造函数
152 | TitleAlert.call(this, data);
153 |
154 | // 取消按钮文案
155 | this.cancel = data.cancel;
156 |
157 | // 创建取消按钮
158 | this.cancelBtn = document.createElement('span');
159 |
160 | // 添加class
161 | this.cancelBtn.className = 'cancel';
162 |
163 | // 设置内容
164 | this.cancelBtn.innerHTML = this.cancel || '取消';
165 | };
166 |
167 | // 继承标题提示框原型方法
168 | CancelAlert.prototype = new Alert();
169 |
170 | CancelAlert.prototype.init = function() {
171 | // 继承标题提示框创建方法
172 | TitleAlert.prototype.init.call(this);
173 |
174 | // 由于取消按钮要添加在末尾,所以在创建完其他组建后添加
175 | this.panel.appendChild(this.cancelBtn);
176 | };
177 |
178 | CancelAlert.prototype.bindEvent = function() {
179 | var self = this;
180 |
181 | TitleAlert.prototype.bindEvent.call(this);
182 |
183 | this.cancelBtn.onclick = function() {
184 | self.fail();
185 | self.hide();
186 | };
187 | };
188 |
189 |
190 |
191 | /*
192 | * 实例化提示框
193 | */
194 | new CancelAlert({
195 | title: '标题提示',
196 | content: '提示内容',
197 | success: function() {
198 | console.log('ok');
199 | },
200 | fail: function() {
201 | console.log('cancel');
202 | }
203 | }).init();
204 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # learn-javascript-design-pattern
2 | 学习javascript设计模式,记录的小例子~
3 |
4 | ### 第一篇 - 面对对象编程
5 |
6 | * [第一章](https://github.com/berwin/learn-javascript-design-pattern/tree/master/chapter1) 灵活的语言————javascript
7 | * [第二章](https://github.com/berwin/learn-javascript-design-pattern/tree/master/chapter2) 面对对象编程
8 |
9 | ### 第二篇 - 创建型设计模式
10 |
11 | * [第三章](https://github.com/berwin/learn-javascript-design-pattern/tree/master/chapter3) 简单工厂模式
12 | * [第四章](https://github.com/berwin/learn-javascript-design-pattern/tree/master/chapter4) 工厂方法模式
13 | * [第五章](https://github.com/berwin/learn-javascript-design-pattern/tree/master/chapter5) 抽象工厂模式
14 | * [第六章](https://github.com/berwin/learn-javascript-design-pattern/tree/master/chapter6) 建造者模式
15 | * [第七章](https://github.com/berwin/learn-javascript-design-pattern/tree/master/chapter7) 原型模式
16 | * [第八章](https://github.com/berwin/learn-javascript-design-pattern/tree/master/chapter8) 单例模式
17 |
18 | ### 第三篇 - 结构型设计模式
19 |
20 | * [第九章](https://github.com/berwin/learn-javascript-design-pattern/tree/master/chapter9) 外观模式
21 | * [第十章](https://github.com/berwin/learn-javascript-design-pattern/tree/master/chapter10) 适配器模式
22 | * 第十一章 代理模式
23 | * [第十二章](https://github.com/berwin/learn-javascript-design-pattern/tree/master/chapter12) 装饰者模式
24 | * [第十三章](https://github.com/berwin/learn-javascript-design-pattern/tree/master/chapter13) 桥接模式
25 | * [第十四章](https://github.com/berwin/learn-javascript-design-pattern/tree/master/chapter14) 组合模式
26 | * [第十五章](https://github.com/berwin/learn-javascript-design-pattern/tree/master/chapter15) 享元模式
27 |
28 | ### 第四篇 - 行为型设计模式
29 |
30 | * [第十六章](https://github.com/berwin/learn-javascript-design-pattern/tree/master/chapter16) 模板方法模式
31 | * [第十七章](https://github.com/berwin/learn-javascript-design-pattern/tree/master/chapter17) 观察者模式
32 | * [第十八章](https://github.com/berwin/learn-javascript-design-pattern/tree/master/chapter18) 状态模式
33 | * [第十九章](https://github.com/berwin/learn-javascript-design-pattern/tree/master/chapter19) 策略模式
34 | * [第二十章](https://github.com/berwin/learn-javascript-design-pattern/tree/master/chapter20) 责任链模式
35 | * [第二十一章](https://github.com/berwin/learn-javascript-design-pattern/tree/master/chapter21) 命令模式
36 | * [第二十二章](https://github.com/berwin/learn-javascript-design-pattern/tree/master/chapter22) 访问者模式
37 | * [第二十三章](https://github.com/berwin/learn-javascript-design-pattern/tree/master/chapter23) 中介者模式
38 | * [第二十四章](https://github.com/berwin/learn-javascript-design-pattern/tree/master/chapter24) 备忘录模式
39 | * [第二十五章](https://github.com/berwin/learn-javascript-design-pattern/tree/master/chapter25) 迭代器模式
40 | * [第二十六章](https://github.com/berwin/learn-javascript-design-pattern/tree/master/chapter26) 解释器模式
41 |
42 | ### 第五篇 - 技巧型设计模式
43 |
44 | * [第二十七章](https://github.com/berwin/learn-javascript-design-pattern/tree/master/chapter27) 链模式
45 | * [第二十八章](https://github.com/berwin/learn-javascript-design-pattern/tree/master/chapter28) 委托模式
46 | * [第二十九章](https://github.com/berwin/learn-javascript-design-pattern/tree/master/chapter29) 数据访问对象模式
47 | * [第三十章](https://github.com/berwin/learn-javascript-design-pattern/tree/master/chapter30) 节流模式
48 | * [第三十一章](https://github.com/berwin/learn-javascript-design-pattern/tree/master/chapter31) 简单模板模式
49 | * [第三十二章](https://github.com/berwin/learn-javascript-design-pattern/tree/master/chapter32) 惰性模式
50 | * [第三十三章](https://github.com/berwin/learn-javascript-design-pattern/tree/master/chapter33) 参与者模式
51 | * [第三十四章](https://github.com/berwin/learn-javascript-design-pattern/tree/master/chapter34) 等待者模式
52 | * [第三十五章](https://github.com/berwin/learn-javascript-design-pattern/tree/master/chapter35) 同步模块模式
53 | * [第三十六章](https://github.com/berwin/learn-javascript-design-pattern/tree/master/chapter36) 异步模块模式
54 | * [第三十七章](https://github.com/berwin/learn-javascript-design-pattern/tree/master/chapter37) Widget模式(其实是实现一个模板引擎)
55 | * [第三十八章](https://github.com/berwin/learn-javascript-design-pattern/tree/master/chapter38) MVC模式
56 | * [第三十九章](https://github.com/berwin/learn-javascript-design-pattern/tree/master/chapter39) MVP模式
57 | * 第四十章 MVVM模式
58 |
59 | # The MIT License (MIT)
60 |
61 | Copyright (c) 2015 Berwin
62 |
63 | Permission is hereby granted, free of charge, to any person obtaining a copy
64 | of this software and associated documentation files (the "Software"), to deal
65 | in the Software without restriction, including without limitation the rights
66 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
67 | copies of the Software, and to permit persons to whom the Software is
68 | furnished to do so, subject to the following conditions:
69 |
70 | The above copyright notice and this permission notice shall be included in all
71 | copies or substantial portions of the Software.
72 |
73 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
74 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
75 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
76 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
77 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
78 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
79 | SOFTWARE.
80 |
81 |
--------------------------------------------------------------------------------
/chapter14/1.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // 背景:经理准备在用户首页添加一个新闻模块,当然新闻的内容是根据用户平时关注的内容挖掘的,因此有的人可能会显示文字新闻,有的人会显示图片新闻,甚至有的人显示的新闻是一个直播链接,方便用户观看比赛。。
4 |
5 | // 寄生式继承
6 | function inheritPrototype(subClass, superClass) {
7 | function F() {}
8 | F.prototype = superClass.prototype;
9 |
10 | var p = new F();
11 | p.constructor = subClass;
12 |
13 | subClass.prototype = p;
14 | }
15 |
16 | /*
17 | * 虚拟类
18 | */
19 | var News = function() {
20 | // 子组件容器
21 | this.children = [];
22 |
23 | // 当前组件元素
24 | this.element = null;
25 | };
26 |
27 | News.prototype = {
28 | init: function() {
29 | throw new Error('请重写你的方法');
30 | },
31 | add: function() {
32 | throw new Error('请重写你的方法');
33 | },
34 | getElement: function() {
35 | throw new Error('请重写你的方法');
36 | }
37 | };
38 |
39 | /*
40 | * 容器类构造函数
41 | */
42 | var Container = function(id, parent) {
43 | // 构造函数继承类
44 | News.call(this);
45 |
46 | // 模块ID
47 | this.id = id;
48 | // 模块的父容器
49 | this.parent = parent;
50 |
51 | // 构建方法
52 | this.init();
53 | };
54 |
55 | inheritPrototype(Container, News);
56 |
57 | Container.prototype.init = function() {
58 | this.element = document.createElement('ul');
59 | this.element.id = this.id;
60 | this.element.className = 'new-container';
61 | };
62 |
63 | Container.prototype.add = function(child) {
64 | // 在子元素容器中插入子元素
65 | this.children.push(child);
66 |
67 | // 插入当前组件元素树中
68 | this.element.appendChild(child.getElement());
69 |
70 | return this;
71 | };
72 |
73 | // 获取当前元素方法
74 | Container.prototype.getElement = function() {
75 | return this.element;
76 | };
77 |
78 | // 显示方法
79 | Container.prototype.show = function() {
80 | this.parent.appendChild(this.element);
81 | };
82 |
83 |
84 |
85 | /*
86 | * 子类
87 | */
88 | var Item = function(classname) {
89 | News.call(this);
90 | this.classname = classname || '';
91 | this.init();
92 | };
93 |
94 | inheritPrototype(Item, News);
95 |
96 | Item.prototype.init = function() {
97 | this.element = document.createElement('li');
98 | this.element.className = this.classname;
99 | };
100 | Item.prototype.add = function(child) {
101 | this.children.push(child);
102 | this.element.appendChild(child.getElement());
103 |
104 | return this;
105 | };
106 | Item.prototype.getElement = function() {
107 | return this.element;
108 | };
109 |
110 |
111 | /*
112 | * 新闻组类
113 | */
114 | var NewsGroup = function(classname) {
115 | News.call(this);
116 | this.className = classname || '';
117 | this.init();
118 | };
119 |
120 | inheritPrototype(NewsGroup, News);
121 |
122 | NewsGroup.prototype.init = function() {
123 | this.element = document.createElement('div');
124 | this.element.className = this.classname;
125 | };
126 | NewsGroup.prototype.add = function(child) {
127 | this.children.push(child);
128 | this.element.appendChild(child.getElement());
129 |
130 | return this;
131 | };
132 | NewsGroup.prototype.getElement = function() {
133 | return this.element;
134 | };
135 |
136 |
137 |
138 | /*
139 | * 创建图片新闻类
140 | */
141 | var ImageNews = function(url, href, classname) {
142 | News.call(this);
143 |
144 | this.url = url || '';
145 | this.href = href || '';
146 | this.classname = classname || 'normal';
147 | this.init();
148 | };
149 |
150 | inheritPrototype(ImageNews, News);
151 |
152 | ImageNews.prototype.init = function() {
153 | this.element = document.createElement('a');
154 | var img = new Image();
155 | img.src = this.url;
156 | this.element.appendChild(img);
157 | this.element.className = 'image-news ' + this.classname;
158 | this.element.href = this.href;
159 | };
160 | ImageNews.prototype.add = function() {};
161 | ImageNews.prototype.getElement = function() {
162 | return this.element;
163 | };
164 |
165 |
166 | /*
167 | * 基类
168 | */
169 | var IconNews = function(text, href, type) {
170 | News.call(this);
171 | this.text = text || '';
172 | this.href = href || '#';
173 | this.type = type || 'video';
174 | this.init();
175 | };
176 |
177 | inheritPrototype(IconNews, News);
178 |
179 | IconNews.prototype.init = function() {
180 | this.element = document.createElement('a');
181 | this.element.innerHTML = this.text;
182 | this.element.href = this.href;
183 | this.element.className = this.classname;
184 | };
185 | IconNews.prototype.add = function() {};
186 | IconNews.prototype.getElement = function() {
187 | return this.element;
188 | };
189 |
190 | /*
191 | * 基类
192 | */
193 | var EasyNews = function(text, href) {
194 | News.call(this);
195 | this.text = text || '';
196 | this.href = href || '';
197 | this.init();
198 | };
199 |
200 | inheritPrototype(EasyNews, News);
201 |
202 | EasyNews.prototype.init = function() {
203 | this.element = document.createElement('a');
204 | this.element.innerHTML = this.text;
205 | this.element.href = this.href;
206 | this.element.className = 'text';
207 | };
208 | EasyNews.prototype.add = function() {};
209 | EasyNews.prototype.getElement = function() {
210 | return this.element;
211 | };
212 |
213 | /*
214 | * 创建新闻模块
215 | */
216 | var news1 = new Container('news', document.body);
217 | news1.add(
218 | new Item('normal').add(
219 | new IconNews('哈哈哈', '#', 'video')
220 | )
221 | ).add(
222 | new Item('normal').add(
223 | new IconNews('呵呵呵', '#', 'live')
224 | )
225 | ).add(
226 | new Item('normal').add(
227 | new NewsGroup('has-img').add(
228 | new ImageNews('img/1.jpg', '#', 'small')
229 | ).add(
230 | new EasyNews('aaaa', '#')
231 | ).add(
232 | new EasyNews('五大雷人跑步机', '#')
233 | )
234 | )
235 | ).show();
236 |
237 |
238 |
239 |
--------------------------------------------------------------------------------