单例模式在前端中很常见, 一个Vue实例,一个JQuery实例,都可以叫做单例模式。单例模式的主要作用一般用来创建命名空间,隔离模块,创建一个小型的代码库时使用,防止代码污染。
命名空间:将代码都隔离在一个对象中,通过对象的方法调用,来进行操作。
var $ = {
g: function() {
return document.getElementById(id)
}
css: function(id ,key, value) {
g(id).style[key] = value
}
}
上面这段代码通过一个对象的来承载查询元素的方法,达到命名空间的目的.
单例模式在常用的代码库中用作模块化。
let moduleName = {
dom:{
}, // dom操作类
event:{
}, // 事件类
string:{
} // 字符串处理
}
当我们需要对相应的方法做拓展时可以直接添加各应用的方法就可以在某一些方法下直接增加拓展的方法。
此时我们尝试用现在学到的方法来规范我们的代码库。
var moduleName = {
utils:{
},
Tool:{
},
ajax:{
},
others:{
}
}
// 此时在调用方法时 即可用moduleName.utils.method() 来调用方法。
在ES6 以前由于不存在静态变量,通常,我们使用闭包解决静态变量的问题。
var constConfig= (function() {
var constCfonig = {
MAX_NUM : 100,
MIN_NUM: 1,
COUNT: 1
}
return {
get: function(name) {
return constCfonig[name] ? constCfonig[name]: null
}
}
})()
var count = constConfig.get('COUNT') // count =1
此时上面的变量就无法被用户修改了。
tips: 这里的变量大写是C语言的代码规范。
什么是惰性单例? 惰性单例: 在项目使用时才创建的实例,即延迟创建的实例。
// 步骤一 创建单体实例的方法
MyNamespace.Singleton = (function() {
function constructor() { // All of the normal singleton code goes here.
// Private members.
var privateAttribute1 = false;
var privateAttribute2 = [1, 2, 3];
function privateMethod1() {
...
}
function privateMethod2(args) {
...
}
return { // Public members.
publicAttribute1: true,
publicAttribute2: 10,
publicMethod1: function() {
...
},
publicMethod2: function(args) {
...
}
}
}
})()
// 步骤二
MyNamespace.Singleton = (function() {
function constructor() {
// 上方的单体方法都在construtor 中.
...
}
return {
getInstance: function() {
// Control code goes here.
}
}
})()
// 步骤三
MyNamespace.Singleton = (function() {
var uniqueInstance; // 创建私有变量保证单例执行
function constructor() {
// 所有上方单例代码都保存在此处
...
}
// 使用惰性模式 创建的单例的调用方法变为 Singleton.getInstance().methodName()
return {
getInstance: function() {
if(!uniqueInstance) { // 如果单例不存在就创建单例.
uniqueInstance = constructor();
}
return uniqueInstance;
}
}
})()
此时上面使用单例的方法或者获取单例的方法变为了 Singleton.getInstance().methodName()。
tips: 上面的方法利用了闭包形成了真正的私有化单例,外部无权修改内部方法,达到变量方法的私有化。
使用单例模式封装一个兼容ie的ajax方法
此时我们应该考虑使用单例进行ajax 封装在单例中进行分支切换。
// 使用分支创建ajax 对象 如果要兼容老旧的浏览器使用ajax,那就可以用这种技术了
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.');
}
}
}
})()
tips: 这里使用了简单工厂模式来进行了不同ajax的适配
如何设计一个可拓展的单例模式库?Jquery是如何进行代码拓展与重写的。
答案会在下期公布。