1、概述 |
所謂單例模式,顧名思義即一個類只有一個實例。chrome
因此,當咱們建立一個實例時,就必須判斷其是否已經存在了這個實例,若是已經存在了這個實例,那麼就返回這個已經存在的實例,無需再建立一個(單例模式嘛,核心就是一個類只有一個 實例);若是不存在,就建立這個實例咯。閉包
好了,單例模式的核心思想以及建立流程大體搞清楚了,那麼咱們就開始看看,在Javascript的世界中,具體該怎麼實現呢?函數
2、實戰一 |
核心思路:利用Javascript的做用域,造成閉包,從而能夠建立私有變量(假設咱們將這個私有變量取名爲instance),而後將建立的實例賦予這個私有變量instance就ok了。每當想建立這個類的實例時,先判斷instance是否已經引用了存在的實例,若是沒有引用,即這個類沒有被建立實例,so建立一個實例,而後將其賦予給instance;若是instance已經引用,即已存在了該類的實例,so無需再建立,直接使用這個instance就ok了。
this
第一步:執行匿名函數,防止命名空間污染。在匿名函數中,首先定義個上述提到的私有變量instance以及一個類。這個類,我假設它有名字(name)和年齡(age)兩個屬性字段以及一個輸出他們名字的方(displayInfo)哈。spa
'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 + 對象字面量,將咱們想,向外暴露的東東,往外拋。prototype
以下:3d
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,若是隻建立了它的一個實例,那麼就只會打印一個日誌哦。
修改代碼以下:code
'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截圖以下:
鑑定完畢,只被實例一次。
3、實戰二 |
思路:利用屬性來判斷是否已存在實例。
什麼意思?
在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); } };
4、實戰三 |
在Javascript的世界裏,this是引用的對象。
還記得JavaScript是怎麼經過new建立對象的麼?
new:
一、建立一個新的對象,這個對象的類型時object;
二、將這個對象的__proto__隱指針指向原型prototype;
三、執行構造函數,當this被說起的時候,表明新建立的對象;
四、返回新建立的對象。
注:假若在最後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); } };