理解設計模式之單例模式(Javascript)

七姊薔薇發表於2019-01-15

單例模式

單例就是確保一個類只有一個例項,任何時候呼叫的例項都是同一個,這個例項只會初始化一次。


方式一

實現步驟:

  1. 最簡單的——物件字面量的方式

其字面量裡可以包含大量的屬性和方法,直接建立好的單例物件。這樣建立的物件變數全域性化了,

var instance={
    prop1: "prop1",
    prop2: "prop2",
    method1: function () {
        console.log('hello world');
    }
}
複製程式碼
  1. 擴充套件該單例物件可以新增自己的私有變數和方法,只暴露公有變數和方法方式,通過閉包的方式來實現。
var mySingleton = function(){

// 私有變數和方法
    var priv_prop='private prop';
    var priv_mtd = function(){
        console.log(priv_prop)
    }
    
// 公有變數和方法,能訪問私有變數和方法
    return {
        pub_mtd: function(){
            priv_mtd()
        },
        pub_prop: 'public prop'
    }
}

var instance = mySingleton();
instance.pub_mtd();  // 輸出 'private prop'
console.log(instance.pub_prop);  // 輸出 'public prop'
複製程式碼

事實上這裡的mySingleton()並不是單例的,只是在第一步上做了擴充套件可以訪問私有變數

var instance2 = mySingleton();
instance === instance2  //false
複製程式碼
  1. 真正的建立例項,每次呼叫的都是同一個物件例項,第一呼叫才會初始化。
var Singleton = (function(){
    // 這裡定義單例程式碼
    var instance;
    function init(){
        return {
            pub_mtd: function(){
                console.log('this is pub_mtd');
            },
            pub_prop:'this is pub_prop'
        }
    };
    
    return {
        getInstance:function(){
            if (!instance){
                instance = init()
            }
            return instance
        }
    }
})()
/*呼叫公有的方法的時候初始化例項:*/
Singleton.getInstance().pub_mtd();

let a=Singleton.getInstance();
let b=Singleton.getInstance();
a === b // true 此時才算是真正的單例
a.pub_mtd === b.pub_mtd //true
a.pub_mtd() //列印出'this is pub_mtd';
複製程式碼

此時才算是真正的單例,任何時候呼叫Singleton.getInstance()都是同一個例項。


其他實現方式

方法1-通過重寫建構函式直接呼叫前一次生成的例項

function Instance(){
    var instance = this;
    
    console.log(111)
    
    this.prop='prop';
    this.mtd=function(){
        console.log(this.prop);
    }
    
    //重寫建構函式
    Instance = function(){
        console.log(222)
        return instance;
    }
}

var a = new Instance()  // 列印出111,同時建構函式被重寫,
var b = new Instance()  // 列印出222,直接返回前一次呼叫快取的instance
a === b // true
複製程式碼

方法2-把首次生成的例項快取到建構函式的屬性上

function Instance(){
    if (typeof Instance.instance === 'object'){
        return Instance.instance
    }
    
    this.prop='prop';
    this.mtd=function(){
        console.log(this.prop);
    };
    
    // 快取
    Instance.instance=this;
    // 隱式返回 this
}

var ins1=new Instance();
var ins2=new Instance();
ins1 === ins2
複製程式碼

方法3-內部重寫建構函式,修改原型屬性,重設建構函式指標

function Instance(){
    var instance;
    console.log(1)
    // 二次呼叫的建構函式
    Instance = function Instance(){
        console.log(2)
        return instance;
    };
    console.log(3)
    // 後期處理原型屬性
    Instance.prototype = this;
    
    // 例項
    instance = new Instance();
    console.log(4)

    // 重設建構函式指標
    instance.constructor = Instance;
    
    instance.prop='prop';
    instance.mtd=function(){
        console.log(instance.prop)
    }
    console.log(5)
    return instance
}
var a = new Instance();
// 13245
var b = new Instance();
// 2

複製程式碼

相關文章