JavaScript之單例實戰


一、概述

所謂單例模式,顧名思義即一個類只有一個實例。

所以,當我們創建一個實例時,就必須判斷其是否已經存在了這個實例,如果已經存在了這個實例,那么就返回這個已經存在的實例,無需再創建一個單例模式嘛,核心就是一個類只有一個 實例;如果不存在,就創建這個實例咯。

好了,單例模式的核心思想以及創建流程大致搞清楚了,那么我們就開始看看,在Javascript的世界中,具體該怎么實現呢?

二、實戰一

核心思路:利用Javascript的作用域,形成閉包,從而可以創建私有變量(假設我們將這個私有變量取名為instance),然后將創建的實例賦予這個私有變量instance就ok了。每當想創建這個類的實例時,先判斷instance是否已經引用了存在的實例,如果沒有引用,即這個類沒有被創建實例,so創建一個實例,然后將其賦予給instance;如果instance已經引用,即已存在了該類的實例,so無需再創建,直接使用這個instance就ok了。

第一步:執行匿名函數,防止命名空間污染。在匿名函數中,首先定義個上述提到的私有變量instance以及一個類。這個類,我假設它有名字(name)和年齡(age)兩個屬性字段以及一個輸出他們名字的方(displayInfo)哈。

'use strict'
var singletonAccepter =(function(){
    //默認將instance賦予null
    var instance = null;
    //類:SupposeClass
    function SupposeClass( args ){
        var args = args || {};
        this.name = args.name || 'Monkey';
        this.age = args.age || 24;
    };
    SupposeClass.prototype = {
        constructor: SupposeClass,
        displayInfo: function(){
            console.log('name: ' + this.name + '   age: ' + this.age);
        }
    };
})();

第二步:利用return + 對象字面量,將我們想,向外暴露的東東,往外拋。

如下:

return {
    //類的名字
    name: 'SupposeClass',
    //創建類的實例方法
    getInstance: function( args ){
        //利用私有變量instance實現單例模式
        if( instance === null ){
            instance = new SupposeClass( args );
        }
        return instance;
    }
};

最后,合並第一步第二步的代碼就形成了一個單例模式啦。

如下:

'use strict'
var singletonAccepter =(function(){
    //默認將instance賦予null
    var instance = null;
    //類:SupposeClass
    function SupposeClass( args ){
        var args = args || {};
        this.name = args.name || 'Monkey';
        this.age = args.age || 24;
    };
    SupposeClass.prototype = {
        constructor: SupposeClass,
        displayInfo: function(){
            console.log('name: ' + this.name + '   age: ' + this.age);
        }
    };
    return {
        //類的名字
        name: 'SupposeClass',
        //創建類的實例方法
        getInstance: function( args ){
            //利用私有變量instance實現單例模式
            if( instance === null ){
                instance = new SupposeClass( args );
            }
            return instance;
        }
    };
})();

接下來,我們檢驗一下寫的這個單例模式。在上述代碼中,在類SupposeClass中加入console.log,如果只創建了它的一個實例,那么就只會打印一個日志哦。
修改代碼如下:

'use strict'
var singletonAccepter =(function(){
    var instance = null;
    function SupposeClass( args ){
        var args = args || {};
        this.name = args.name || 'Monkey';
        this.age = args.age || 24;
        //檢驗單例模式
        console.log('this is created!');
    };
    SupposeClass.prototype = {
        constructor: SupposeClass,
        displayInfo: function(){
            console.log('name: ' + this.name + '   age: ' + this.age);
        }
    };
    return {
        name: 'SupposeClass',
        getInstance: function( args ){
            if( instance === null ){
                instance = new SupposeClass( args );
            }
            return instance;
        }
    };
})();

調用兩次getInstance方法,看看打印幾條記錄

singletonAccepter.getInstance();
singletonAccepter.getInstance();

執行代碼,打開chrome截圖如下:

鑒定完畢,只被實例一次。

三、實戰二

思路:利用屬性來判斷是否已存在實例。
什么意思?
在Javascript的世界里,類(function)不也是對象嘛,so對其賦予一個屬性instance,用來引用創建的實例,通過判斷instance是否已引用創建的實例就OK咯。

如下:

function singletonAccepter( args ){
    //判斷Universe.instance是否已存在實例
    if(typeof singletonAccepter.instance === 'object'){
        return singletonAccepter.instance;
    }
    this.name = args.name || 'Monkey';
    this.age = args.age || 24;
    singletonAccepter.instance = this;
};
singletonAccepter.prototype = {
    constructor: singletonAccepter,
    displayInfo: function(){
        console.log('name: ' + this.name + '   age: ' + this.age);
    }
};
四、實戰三

在Javascript的世界里,this是引用的對象。
還記得JavaScript是怎么通過new創建對象的么?
new:
  1、創建一個新的對象,這個對象的類型時object;
  2、將這個對象的__proto__隱指針指向原型prototype;
  3、執行構造函數,當this被提及的時候,代表新創建的對象;
  4、返回新創建的對象。
  注:倘若在最后return了,那么return的是基本類型,例如3,則無效;否則是引用類型,則返回這個引用類型。


注意第3點了么?

當new后,this代表新創建的對象。so,我們可以利用閉包,在類中聲明一個變量instance來引用創建的實例。然后再重寫類,就OK啦。

如下:

function singletonAccepter( args ){
    var instance = null;
    var args = args || {};
    this.name = args.name || 'Monkey';
    this.age = args.age || 24;
    //將instance引用創建的實例this
    instance = this;
    //重寫構造函數
    singletonAccepter = function(){
        return instance;
    }
};
singletonAccepter.prototype = {
    constructor: singletonAccepter,
    displayInfo: function(){
        console.log('name: ' + this.name + '   age: ' + this.age);
    }
};


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM