JavaScript设计模式:读书笔记(未完)

时间:2020-12-09 04:20:59

该篇随我读书的进度持续更新
阅读书目:《JavaScript设计模式》

  1. 2016/3/30
  2. 2016/3/31
  3. 2016/4/8

2016/3/30:

模式是一种可复用的解决方案,可用于解决软件设计中遇到的常见问题./将解决问题的方法制作成模板,并且这些模板可应用于多种不同的情况.
有效模式的附加要求:适合性,实用性,适用性.

模式的优点:

  • 防止局部问题引起大问题,模式让我们的代码更有组织性
  • 模式通常是通用的解决方式,不管我们开发哪种应用程序,都可以用模式优化我们代码的结构
  • 模式确实可以让我们避免代码复用,使代码更整洁
  • 使用模式方便我们与工作伙伴一起工作时进行沟通和交流

优秀模式有以下的特点

  • 解决特殊问题
  • 没有显而易见的解决方案-间接提供解决问题的方案
  • 证明了作用与描述相一致
  • 描述了一种关系,从正式描述能深入解释它与代码关系的系统结构和机制

反模式:

  • 描述一种针对某个特定问题的不良解决方案,该方案会导致糟糕的情况发生
  • 描述如何摆脱前述的糟糕情况以及如何创造好的解决方案

JavaScript中的反模式示例:

  • 在全局上下文中定义大量的变量污染全局命名空间(就是乱使用全局变量)
  • 向setTimeout/setInterval传递字符串,这会导致出发eval()的内部使用
  • 修改Object类的原型
  • 内联形式使用JavaScript,它是不可改变的
  • 滥用document.write

设计模式:
确定->包含的类和实例,它们的角色,协作方式,职责分配

  1. 创建型设计模式
    处理对象创建机制,以适合给定情况的方式来创建对象.旨在通过控制创建过程来解决减少创建对象的基本方法可能导致的项目复杂性
    Constructor(构造器),Factory(工厂),Abstract(抽象),Prototype(原型),Singleton(单例),Builder(生成器)都属于创建型设计模式.
  2. 结构型设计模式
    找出不同对象之间建立关系的简单方法,确保系统某一部分发生变化时,系统整个结构不需要同时改变,对于不适合某一特定目的需要改变的系统部分,模式也能帮助进行重组.
    Decorator(装饰者),Facade(外观),Flyweight(享元),Adapter(适配器),Proxy(代理)都属于结构型设计模式.
  3. 行为设计模式
    专注于改善简化系统中不同对象的通信
    Iterator(迭代器),Mediator(中介者),Observer(观察者),Visitor(访问者)都属于行为设计模式.

2016/3/31:

Constructor(构造器)模式:
<经典OOPL中,Constructor是一种在内存已分配给该对象的情况下,用于初始化新创建对象的特殊方法.>
JavaScript中,创建新对象有两种方法:
1. var newObj = {};
2. var newObj = new Object();
以上两种方法都创建了空对象.
赋值方法有4种:
newObj.some = "hello world";
newObj["some"] = "hello world";
以上两种兼容ECMAScript3
Object.defineProperty(newObj,"some",{value:"hello world"});//mdn链接
Object.defineProperties(newObj,{"some":{value:"hello world"},"other":{value:"goodbye"}});//mdn链接
以上两种方法属于ECMAScript5

基本构造器:

function people(name,age){
this.name = name;
this.age = age;
this.toString = function(){
return this.name;
};
}

问题:toString这样的函数为每个people构造器创建的新对象而重新分别定义了.

带原型的构造器:

function people(name,age){
this.name = name;
this.age = age;
}
people.prototype.toString = function(){
return this.name;
}

这样就可以单一实例在所有people对象之间共享了.

Module(模块)模式
在JavaScript中,实现模块的方法:

  • 对象字面量表示法(对象表达式)
  • Module模式
  • AMD模块
  • CommonJS模块
  • ECMAScript Harmony模块

后三种在后面讨论,目前学习前两种

对象字面量表示法:
对象字面量不需要new来实例化,但不能用于语句开头,这会导致{被解读为一个块的开始.对象外部,新成员赋值可以用myModule.property = "Value";
使用对象字面量有助于封装和组织代码.

Module(模块)模式:
Module模式最初定义为一种在传统软件工程中为类提供私有和公有封装的方法.
而在JavaScript中,Module模式用于进一步模拟类的概念.我们通过该方式,能够使一个单独的对象拥有公有/私有方法和变量,使函数名与页面其他脚本定义的函数冲突可能性降低.
JavaScript中没有真正意义上的"私有",所以我们使用作用域来模拟该概念

//函数字面量
var myMoudle = {
myProperty:"property",
myConfig:{
language:"cn"
},
myFunction:function(){
return "myFunction";
}
}; //Module mode
var newMoudle = (function() {
//private
var innerVar = "test"; return {
//publish
displayInnerVar = function() {
return innerVar;
} };
})();

2016/4/8:
Revealing Module(揭示模块)模式:
Revealing Module模块模式是对Module模式的优化,它规定了在私有范围内定义所有函数和变量,返回值则为一个匿名对象,它拥有指向私有范围内某个函数的指针,而这个在私有范围内定义的函数就是我们的公有函数。这样解释大概比较模糊,我们还是看看代码吧。

var testRevealingModule = function(){
var privateVar = "private",publicVar = "public";
function privateGet(){return privateVar;}
function publicSet(text){publicVar = text;}
function privateSet(text){privateVar = text;}
return {
publicVar:publicVar,
publicSet:publicSet
}
}

注意,函数的定义都是在私有作用于内进行定义的,这样对于我们代码的可读性有较大的提升,但是这个模式也有自己的缺点,如果私有函数引用了一个公有函数,在需要打补丁的时候,公有函数是不能被覆盖的,因为私有函数将继续引用私有实现,该模式不适用于公有成员,只适用于函数,引用私有变量的公有对象成员也遵守无补丁规则
可以说,Revealing Module比原始Module更加的脆弱,但是对于我们代码的可读性有较大的提升。

Singleton(单例)模式:
简单来说就是实例化一次的类吧,实例不存在的情况下,可以通过一个方法创建一个类来实现创建类的新实例;如果实例存在,则返回该对象的引用。
而Singleton与静态类的区别在于我们能够推迟它的初始化,而这通常是因为我们需要一些初始化时可能无法获取的信息。
在JavaScript中,Singleton通常用于充当共享资源命名空间,从全局命名空间中隔离出代码实现,为函数提供单一访问点。

var config = function(){
var flag;
function init(){
var url = "www.baidu.com",count = [];
var radomNum = Math.random();
function getUrl(){
return url;
}
function constructure(){
count.push("1");
}
return{
easyTest:constructure,
getUrl:getUrl,
count:count
};
}
return{
getConfig:function(){
if(!flag){
flag = init();
return flag;
}
else{
return flag;
}
}
};
}();
console.log(config.getConfig().getUrl()); //www.baidu.com
var testA = config.getConfig();
var testB = config.getConfig();
console.log(testA.count);// []
testA.easyTest();
console.log(testB.count);// ["1"]

1.当类只能有一个实例而且客户可以从一个众所周知的访问点访问它时(config.getConfig())
2.该唯一的实例应该是通过子类化可拓展的,并且客户无需更改代码就能使用一个拓展的实例。
满足以上两点的时候,我们就可以使用Singleton模式。
当然Singleton的应用场景还有许多,我们也可以这样写Singleton:

config.getConfig = function(){
if(this.flag == null){
if(isFoo()){
this.flag = new Fooconfig();//应该为Basicconfig的子类,并实现相同的接口
}else{
this.flag = new Basicconfig();
}
}
}

这与Factory(工厂)模式看起来有些相似,但是并不一样。
Singleton可以用于协调不同对象,但是Singleton的测试会较为困难。

Observer(观察者)模式:
一个对象(subject)维持一系列依赖于它的对象(观察者),将有关状态的任何变更自动通知给它们。
Observer模式的实现组件:

  1. Subject(目标):维护一系列的观察者,方便添加删除观察者
  2. Observer(观察者):为目标状态发生改变时需获得通知的对象提供一个更新接口
  3. ConcreteSubject(具体目标):状态发生改变时,对Observer发出通知,储存ConcreteObserver的状态
  4. ConcreteObserver(具体观察者):储存指向ConcreteSubject的引用,实现Observer的更新接口

我们用代码来理解下吧