一:单体的基本结构

最简单的单体,实际就是一个对象字面量:
var Singleton = {
attribute1: true,
attribute2: , method1: function() { },
method2: function(arg) { }
};
二:划分命名空间
单体一个很重要的功能就是划分命名空间,这节其实没什么好说的。。
然后,最好的做法是将命名空间再进一步统一,使自己的所有代码都通过一个全局对象来访问,例子:
var GiantCorp = {};

GiantCorp.Common = {
// A singleton with common methods used by all objects and modules.
}; GiantCorp.ErrorCodes = {
// An object literal used to store data.
}; GiantCorp.PageHandler = {
// A singleton with page specific methods and attributes.
};
然后这样的话,与外部的代码发生冲突的可能性就超级少了
三:用作特定网页专用代码的包装器的单体
单体的另一个重要的功能就是包装网页专用代码:
Namespace.PageName = {

  // Page constants.
CONSTANT_1: true,
CONSTANT_2: , // Page methods.
method1: function() { },
method2: function() { }, // Initialization method.
init: function() { }
}
然后就调用这些代码
addLoadEvent(Namespace.PageName.init);
接下来举一个实际使用的例子:我们现在写网页基本上必写的就是用ajax提交表单,那么我们怎样用单体来包装这些代码呢?下面就是一个演示:
先来反例(我自己之前的做法~~~):
var formID = document.getElementById("form");
formID.addEventListener('submit',formSubmit,false); function formSubmit(e) {
//阻止表单默认动作,然后用ajax发送数据
//接受数据之后调用callBack函数
} function callBack(data) {
//用ajax提交表单之后的回调函数
这样的话污染了超级多的全局变量~~~
然后学习这章之后的做法~~~
var GiantCorp = window.GiantCorp || {};
GiantCorp.RegPage = {
formID: 'form',
callBack: function(data) {
//用ajax提交表单之后的回调函数
},
formSubmit: function(e) {
//阻止表单默认动作,然后用ajax发送数据
//接受数据之后调用callBack函数
},
init: function(e) {
GiantCorp.RegPage.formEl = document.getElementById(GiantCorp.RegPage.formID);
GiantCorp.RegPage.formEl.addEventListener('submit',GiantCorp.RegPage.formSubmit,false);
}
} GiantCorp.RegPage.init();
注意第一行代码,意思就是如果之前定义过GiantCorp的话就不管,不然就赋予一个空对象给GiantCorp,这样的代码在很多地方都会看到。
四:拥有私用成员的单体
拥有私用成员的最简单方法就是在属性前加下划线_来区分:
GiantCorp.DataParser = {
// Private methods.
_stripWhitespace: function(str) {
return str.replace(/\s+/, '');
},
_stringSplit: function(str, delimiter) {
return str.split(delimiter);
}, // Public method.
stringToArray: function(str, delimiter, stripWS) {
if(stripWS) {
str = this._stripWhitespace(str);
}
var outputArray = this._stringSplit(str, delimiter);
return outputArray;
}
};
上面的代码不用去理解它,看到下划线_就把它当成是私有属性就可以了
此外stringToArray的函数里面用了this来直接调用单体里面的其他方法,不过使用起来注意它有时候指向的对象的问题!
接下来是使用闭包来实现真正拥有私用成员的单体:
MyNamespace.Singleton = (function() {
// Private members.
var privateAttribute1 = false;
var privateAttribute2 = [, , ]; function privateMethod1() {
...
}
function privateMethod2(args) {
...
} return { // Public members.
publicAttribute1: true,
publicAttribute2: , publicMethod1: function() {
...
},
publicMethod2: function(args) {
...
}
};
})();
注意是公共成员都是放在return里面的,其他都是私有的。
这种模式是JavaScript中最流行,应用最广泛的模式之一
五:惰性实例化
又来一个比较高级的做法,那就是惰性实例化:当我们需要用到这段代码的时候才创建它。换种方法说就是这样调用其方法:Singleton.getInstance().methodName(),而不是这样调用:Singleton.methodName()。其中getInstance方法会检查该单体是否已经被实例化。如果还没有,那么它将创建并返回其实例,如果单体已经实例过,那么它将返回现有实例。
 
实现步骤一(单体的所有代码移动一个名为constructor的方法中):
MyNamespace.Singleton = (function() {

  function constructor() { // All of the normal singleton code goes here.
// Private members.
var privateAttribute1 = false;
var privateAttribute2 = [, , ]; function privateMethod1() {
...
}
function privateMethod2(args) {
...
} return { // Public members.
publicAttribute1: true,
publicAttribute2: , publicMethod1: function() {
...
},
publicMethod2: function(args) {
...
}
}
} })();
上面注意constructor是包含单体里面所有代码的。
实现步骤二(创建一个单体控制的函数,并返回到单体):
MyNamespace.Singleton = (function() {

  function constructor() { // All of the normal singleton code goes here.
...
} return {
getInstance: function() {
// Control code goes here.
}
}
})();
实现步骤三(创建个私有变量用于判断是否已经实例化,并且在getInstance实现判断逻辑):
MyNamespace.Singleton = (function() {

  var uniqueInstance; // Private attribute that holds the single instance.

  function constructor() { // All of the normal singleton code goes here.
...
} return {
getInstance: function() {
if(!uniqueInstance) { // Instantiate only if the instance doesn't exist.
uniqueInstance = constructor();
}
return uniqueInstance;
}
}
})();
此外,可以用 var MNS = MyNamespace.Singleton的方法简化命名空间,但是要注意this指向问题!
六:分支
利用分支可以实现判断浏览器支持哪一种代码,然后对该浏览器使用专用的代码:
MyNamespace.Singleton = (function() {
var objectA = {
method1: function() {
...
},
method2: function() {
...
}
};
var objectB = {
method1: function() {
...
},
method2: function() {
...
}
}; return (someCondition) ? objectA : objectB;
})();
用上面这样的分支我们就可以用来实现如果是IE8就返回第一种单体,如果不是就返回第二种单体了。
七:示例:用分支技术创建XHR对象
如果要兼容老旧的浏览器使用ajax,那就可以用这种技术了
例子:
/* SimpleXhrFactory singleton, step 1. */

var SimpleXhrFactory = (function() {

  // The three branches.
var standard = {
createXhrObject: function() {
return new XMLHttpRequest();
}
};
var activeXNew = {
createXhrObject: function() {
return new ActiveXObject('Msxml2.XMLHTTP');
}
};
var activeXOld = {
createXhrObject: function() {
return new ActiveXObject('Microsoft.XMLHTTP');
}
}; })(); /* SimpleXhrFactory singleton, step 2. */ var SimpleXhrFactory = (function() { // The three branches.
var standard = {
createXhrObject: function() {
return new XMLHttpRequest();
}
};
var activeXNew = {
createXhrObject: function() {
return new ActiveXObject('Msxml2.XMLHTTP');
}
};
var activeXOld = {
createXhrObject: function() {
return new ActiveXObject('Microsoft.XMLHTTP');
}
}; // To assign the branch, try each method; return whatever doesn't fail.
var testObject;
try {
testObject = standard.createXhrObject();
return standard; // Return this if no error was thrown.
}
catch(e) {
try {
testObject = activeXNew.createXhrObject();
return activeXNew; // Return this if no error was thrown.
}
catch(e) {
try {
testObject = activeXOld.createXhrObject();
return activeXOld; // Return this if no error was thrown.
}
catch(e) {
throw new Error('No XHR object found in this environment.');
}
}
} })();

《javascript设计模式》笔记之第五章:单体模式的更多相关文章

  1. javascript设计模式学习之十五——装饰者模式

    一.装饰者模式定义 装饰者模式可以动态地给某个对象添加一些额外的职责,而不会影响从这个类中派生的其他对象.这种为对象动态添加职责的方式就称为装饰者模式.装饰者对象和它所装饰的对象拥有一致的接口,对于用 ...

  2. [书籍翻译] 《JavaScript并发编程》第五章 使用Web Workers

    本文是我翻译<JavaScript Concurrency>书籍的第五章 使用Web Workers,该书主要以Promises.Generator.Web workers等技术来讲解Ja ...

  3. Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第五章:渲染流水线

    原文:Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第五章:渲染流水线 学习目标 了解几个用以表达真实场景的标志和2D图像 ...

  4. Java 设计模式系列(十五)迭代器模式(Iterator)

    Java 设计模式系列(十五)迭代器模式(Iterator) 迭代器模式又叫游标(Cursor)模式,是对象的行为模式.迭代子模式可以顺序地访问一个聚集中的元素而不必暴露聚集的内部表象(interna ...

  5. Javascript设计模式理论与实战:工厂方法模式

    本文从简单工厂模式的缺点说起,引入工厂方法模式,介绍的工厂方法模式的基本知识,实现要点和应用场景,最后举例进行说明工厂方法模式的应用.在之前的<Javascript设计模式理论与实战:简单工厂模 ...

  6. JavaScript DOM编程艺术-学习笔记(第五章、第六章)

    第五章: 1.题外话:首先大声疾呼,"js无罪",有罪的是滥用js的那些人.js的father 布兰登-艾克,当初为了应付工作,10天就赶出了这个js,事后还说人家js是c语言和s ...

  7. Javascript设计模式笔记

    Javascript是越来越厉害了,一统前后端开发.于是最近把设计模式又看了一遍,顺便做了个笔记,以方便自己和他人共同学习. 笔记连载详见:http://www.meteorcn.net/wordpr ...

  8. 《LINUX内核设计与实现》读书笔记之第五章

    第五章——系统调用 5.1 与内核通信 1.为用户空间提供一种硬件的抽象接口 2.保证系统稳定和安全 3.除异常和陷入,是内核唯一的合法入口. API.POSIX和C库 关于Unix接口设计:提供机制 ...

  9. Linux内核分析 读书笔记 (第五章)

    第五章 系统调用 5.1 与内核通信 1.调用在用户空间进程和硬件设备之间添加了一个中间层.该层主要作用有三个: 为用户空间提供了硬件的抽象接口. 系统调用保证了系统的稳定和安全. 实现多任务和虚拟内 ...

随机推荐

  1. codeforces B. Multitasking 解题报告

    题目链接:http://codeforces.com/problemset/problem/384/B 题目意思:给出n个数组,每个数组包括m个数字,当k = 0 时,需要把n个数组都按照从小到大的顺 ...

  2. C#开发遇到的常见问题及知识点

    今天遇到的类型初始值设定项引发异常的原因是:类没有添加[Serializable]属性. this.DialogResult = System.Windows.Forms.DialogResult.O ...

  3. Swing项目编译成exe,并且打包成安装文件(一)

    我们一般用java做Swing项目的时候一般都是只能在Myeclipse里面运行,那么怎么把我们的项目打包成exe可以直接双击运行呢? 初始工作:为了不让用户安装java环境,所以我们先新建一个文件夹 ...

  4. hdu 2188 悼念512汶川大地震遇难同胞——选拔志愿者(Bash Game)

    题意:从0开始捐款,每次不超过m元,首先达到n元的获胜 思路:等同于从n开始,每次取不超过m,首先达到0的获胜.(Bash Game) #include<iostream> #includ ...

  5. JQ里的this与$(this)

    网上有很多关于jQuery的this和$(this)的介绍,大多数只是理清了this和$(this)的指向,其实它是有应用场所的,不能一概而论在jQuery调用成员函数时,this就是指向dom对象. ...

  6. codevs 4768跳石头

    传送门 4768 跳石头  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 黄金 Gold  题目描述 Description 一年一度的“跳石头”比赛又要开始了! 这项比赛将在 ...

  7. MTK touchscreen 流程

    1. kernel-3.18/drivers/input/touchscreen/mediatek/tpd_common_probe.c static int __init tpd_probe_ini ...

  8. 给DataTable中添加一行数据

    一.如果该DataTable有两列,列的名称是Name,Age,且该DataTable的名称是dt; DataRow dr = dt.NewRow(); dr["Name"] = ...

  9. vue全局配置

    Vue.config 是一个对象,包含Vue的全局配置.可以在启动应用之前修改下列的属性: Vue.config.slient=true;      取消Vue所有的日志与警告   默认值false ...

  10. 网卡流量检测.py

    network_speed网卡流量检测 #!/usr/bin/env python #coding:utf-8 import sys import os import atexit import ti ...