JS单例模式 (Singleton)
单例模式的核心是确保 一个特定类只有一个实例,并提供这个实例的全局访问
-
在构造函数的静态属性中缓存该实例
function Sington() { if(typeof Sington.instance === 'object') { return Sington.instance } Sington.instance = this return this } var a = new Sington() var b = new Sington() console.log(a === b) // true
这种方式的缺点在于:
instance
属性是公开可访问的属性,在外部代码中可能会修改该属性。 -
把实例封装在闭包中
function Sington() { var instance = this // 重写构造函数 Sington = function() { return instance } } var a = new Sington() var b = new Sington() console.log(a === b) // true
当第一次调用构造函数时,它正常返回
this
,然后在以后调用时,它将会执行重写构造函数,这个构造函数通过闭包访问了私有instance
变量,并且简单的返回了该instance
。这样可以保证该实例的私有性并且保证该实例不会在构造函数之外被修改,代价是带来了额外的闭包开销。
-
有时候对于单例对象需要延迟创建,所以在单例中还存在一种延迟创建的形式( 惰性单例)
var Singleton = (function() { var instance Singleton = function() { if (instance) return instance return instance = this } return Singleton })() var a = new Singleton('a') var b = new Singleton('b') console.log(a===b)
这种方法有缺点:不符合单一职责原则,这个对象其实负责了两个功能:单例和创建对象
-
改进版惰性单例
var Singleton = function(Obj) { var instance Singleton = function(...args) { if (instance) return instance return (instance = new Obj(...args)) } return Singleton } var People = function(name, age) { this.name = name this.age = age } var peopleSingleton = Singleton(People) var a = new peopleSingleton('a', 12) var b = new peopleSingleton('b', 11) console.log(a) // People { name: 'a', age: 12 } console.log(b) // People { name: 'a', age: 12 } console.log(a === b) // true
-
单例模式应用场景 – 页面弹框
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> </head> <body> <button id="loginBtn">click me</button> <script> var getSingle = function(fn) { var result return function() { return result || (result = fn.apply(this, arguments)) } } var createLoginLayer = function() { var div = document.createElement('div') div.innerHTML = '我是登录浮窗' div.style.display = 'none' div.style.border = '1px solid #ccc' document.body.appendChild(div) return div } var createSingleLoginLayer = getSingle(createLoginLayer) document.getElementById('loginBtn').onclick = function() { var loginLayer = createSingleLoginLayer() loginLayer.style.display = 'block' } </script> </body> </html>