单例模式又被称为单体模式,是只允许实例化一次的对象类。实现的方法一般是先判断实例中是否存在,如果存在则直接返回,不存在就创建了再返回,这样就确保了一个类只有一个实例对象。在JavaScript中,单例模式作为一个命名空间提供者,从全局命名空间里提供一个唯一的访问点来访问改对象。
单例的常见作用:
- 模块间通信
- 系统中某个类的对象只能存在一个
- 保护自己的属性和方法
应用
系统中某个类的对象只能存在一个
例如,我们要实现点击按钮,弹出一个模态框
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <style> div{ width:200px; height:200px; border:1px solid #09f; position: absolute; } </style> </head> <body> <input type="button" value="弹窗"> <script> var oBtn = document.querySelector("input"), offset = 20, index = 1; function Module(pos){ this.offset = pos || 20; }; Module.prototype.create = function(){ var oDiv = document.createElement("div"); oDiv.style.left = (++index) * offset + 'px'; oDiv.style.top = (++index) * offset + 'px'; oDiv.innerHTML = '普通弹窗'; return oDiv; }; oBtn.onclick = function(){ var oDiv = new Module(); document.body.appendChild(oDiv.create()); }; </script> </body> </html>
我们希望的是,不管点击按钮多少次,都只出现一个模态框,但结果却是下面这样的:
这个时候就需要用单例模式进行改造:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <style> div{ width:200px; height:200px; border:1px solid #09f; position: absolute; } </style> </head> <body> <input type="button" value="弹窗1"> <input type="button" value="弹窗2"> <script> var oBtn = document.querySelectorAll("input"), offset = 20, index = 1; function Module(pos){ this.offset = pos || 20; }; Module.prototype.create = function(){ var oDiv = document.createElement("div"); oDiv.style.left = (++index) * offset + 'px'; oDiv.style.top = (++index) * offset + 'px'; oDiv.innerHTML = '单例模式弹窗'; return oDiv; }; Module.one = (function(){ var ins = null, isExist = false; return function(pos){ if(!ins) ins = new Module(pos); if(!isExist){ document.body.appendChild(ins.create()); isExist = true; } } })(); oBtn[0].onclick = function(){ Module.one(10); }; oBtn[1].onclick = function(){ Module.one(10); }; </script> </body> </html>
在Module.one中通过变量isExist的两种状态和闭包特性控制元素只能被添加一次,就可以实现只能弹出一个模态框的效果了。
保护自己的属性和方法
单例模式经常为我们提供一个命名空间。例如我们使用过的jQuery,单例模式就为它提供了一个命名空间jQuery。
在上面的代码中,因为可用的单词有限,命名十分简单,但是如果后续后其他的同事在维护代码的时候,出现了同名的方法或变量,这里的业务逻辑就会出现问题,此时就需要用命名空间来约束每一个人定义的变量:
由于对象中的this指代当前对象,所以,上面两种写法是等效的。