国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 編程 > JavaScript > 正文

JavaScript實(shí)現(xiàn)設(shè)計(jì)模式中的單例模式的一些技巧總結(jié)

2019-11-20 10:01:48
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

一、使用全局變量保存單例

這是最簡(jiǎn)單的實(shí)現(xiàn)方法

function Person(){   this.createTime=new Date(); } var instance=new Person(); function getInstance(){   return instance; } 

加載該js時(shí)就創(chuàng)建一個(gè)Person對(duì)象,保存到instance全局變量中,每次使用都取這個(gè)對(duì)象。如果一次都沒(méi)使用,那么創(chuàng)建的這個(gè)對(duì)象則浪費(fèi)了,我們可以優(yōu)化一下,

var instance function getInstance(){   if(!instance){     instance=new Person();   }   return instance; } 

這樣,第一次使用時(shí)才創(chuàng)建對(duì)象。
這個(gè)方法的缺點(diǎn)是,instance是全局的變量,在多人合作或者開發(fā)周期比較長(zhǎng)的情況下,很難保證instance不會(huì)被其它代碼修改或覆蓋,很可能到調(diào)用的時(shí)候,發(fā)現(xiàn)instance根本就不是Person對(duì)象。
我們考慮下使用閉包來(lái)封裝起instance,使它不再是全局變量就可以解決這個(gè)問(wèn)題了

二、閉包創(chuàng)建對(duì)象

var getInstance(){ var instance; return function(){     if(!instance){       instance=new Person();     }     return instance;   } }(); 

這樣,instance就被封裝起來(lái)了,不用擔(dān)心被修改了。
現(xiàn)在通過(guò)getInstance()函數(shù)可以獲得單例了。新的問(wèn)題,如果我通過(guò)new Person()來(lái)創(chuàng)建對(duì)象,獲得的還是多個(gè)對(duì)象,javascript又不可以像java一樣把構(gòu)造器私有化。那怎么樣可以讓多次new出來(lái)的對(duì)象都是一個(gè)實(shí)例呢?

三、構(gòu)造函數(shù)的靜態(tài)屬性緩存實(shí)例

先看代碼

function Person(){   //如果已經(jīng)緩存了實(shí)例,則直接返回緩存的實(shí)例   if(typeof Person.instance==='object'){     return Person.instance;   }   this.createTime=new Date();   //緩存實(shí)例   Person.instance=this;   return this; } 

從代碼可以看到,第一次new時(shí),if的條件返回false,會(huì)往下走,初始化對(duì)象,然后保存對(duì)象到Person.instance這個(gè)靜態(tài)屬性中。
第二次new 時(shí),if的條件返回true,直接返回Person.instance,不會(huì)再往下運(yùn)行初始化的代碼。所以不管new幾次,返回的都是第一次創(chuàng)建的對(duì)象。

這個(gè)方法的缺點(diǎn)和方法一的缺點(diǎn)一樣,Person.instance也是公開屬性,有可能會(huì)被修改。

我們參考方法二,使用閉包來(lái)封裝一個(gè),也許就能解決該問(wèn)題了

四、重寫構(gòu)造函數(shù)

這個(gè)方法要使用閉包,但不能像方法二那么簡(jiǎn)單,我們需要重寫構(gòu)造函數(shù)。

function Person(){   //緩存實(shí)例   var instance=this;   this.createTime=new Date();   //重寫構(gòu)造函數(shù)   Person=function(){     return instance;   } } 

第一次new 時(shí),調(diào)用原始構(gòu)造函數(shù)先緩存該實(shí)例,然后再初始化,同時(shí),重寫該構(gòu)造函數(shù)。以后再new 時(shí),永遠(yuǎn)調(diào)用不到原始的構(gòu)造函數(shù)了,只能調(diào)用到重寫后的構(gòu)造函數(shù),而這個(gè)函數(shù)總是返回緩存的instance.
上面的方法似乎沒(méi)什么問(wèn)題,但通過(guò)下面的測(cè)試,可以發(fā)現(xiàn)問(wèn)題

//向原型添加屬性 Person.prototype.prop1=true; var p1=new Person(); //在創(chuàng)建初始化對(duì)象后,再次向該原型添加屬性 Person.prototype.prop2=true; var p2=new Person(); //開始測(cè)試 console.log(p1.prop1);//結(jié)果為true console.log(p2.prop1);//結(jié)果為true console.log(p1.prop2);//結(jié)果為undefined console.log(p2.prop2);//結(jié)果為undefined console.log(p1.constructor===Person);//結(jié)果為false console.log(p2.constructor===Person);//結(jié)果為false 

我們預(yù)期中的結(jié)果,應(yīng)該是全都是true。
分析一下上述測(cè)試代碼

Person.prototype.prop1=true;是在原始構(gòu)造函數(shù)的原型下增加了prop1這個(gè)屬性,并賦值

而在執(zhí)行 var p1=new Person();之后,Person這個(gè)構(gòu)造函數(shù)已經(jīng)被重寫了

所以Person.prototype.prop2=true;是在新的原型下增加prop2這個(gè)屬性

var p2=new Person(); p2和p1實(shí)際上是同一個(gè)對(duì)象,即原始構(gòu)造函數(shù)創(chuàng)建的對(duì)象

所以p1 p2都有prop1這個(gè)屬性,而沒(méi)有prop2這個(gè)屬性

同樣的,p1 p2的constructor指向的也是原始的構(gòu)造函數(shù),而Person此時(shí)已不是原來(lái)那個(gè)函數(shù)了

為了能按預(yù)期的結(jié)果那樣運(yùn)行,可以通過(guò)一些修改來(lái)實(shí)現(xiàn)

function Person(){   //緩存實(shí)例   var instance=this;   //重寫構(gòu)造函數(shù)   Person=function(){     return instance;   }   //保留原型屬性   Person.prototype=this;   //實(shí)例   instance=new Person();   //重置構(gòu)造函數(shù)引用   instance.constructor=Person;   //其他初始化   instance.createTime=new Date();    return instance; } 

再運(yùn)行前面的測(cè)試代碼,結(jié)果都是true了。

五、惰性加載:
在大型或復(fù)雜的項(xiàng)目中,起到了優(yōu)化的作用:那些開銷較大卻很少用到的組件可以被包裝到惰性加載單例中,示例程序:

/* Singleton with Private Members, step 3. */MyNamespace.Singleton = (function() { // Private members. var privateAttribute1 = false; var privateAttribute2 = [1, 2, 3]; function privateMethod1() {  ... } function privateMethod2(args) {  ... } return { // Public members.  publicAttribute1: true,  publicAttribute2: 10,  publicMethod1: function() {   ...  },  publicMethod2: function(args) {   ...  } };})();/* General skeleton for a lazy loading singleton, step 1. */MyNamespace.Singleton = (function() { function constructor() { // All of the normal singleton code goes here.  // Private members.  var privateAttribute1 = false;  var privateAttribute2 = [1, 2, 3];  function privateMethod1() {   ...  }  function privateMethod2(args) {   ...  }  return { // Public members.   publicAttribute1: true,   publicAttribute2: 10,   publicMethod1: function() {    ...   },   publicMethod2: function(args) {    ...   }  } }})();/* General skeleton for a lazy loading singleton, step 2. */MyNamespace.Singleton = (function() { function constructor() { // All of the normal singleton code goes here.  ... } return {  getInstance: function() {   // Control code goes here.  } }})();/* General skeleton for a lazy loading singleton, step 3. */MyNamespace.Singleton = (function() { var uniqueInstance; // Private attribute that holds the single instance. function constructor() { // All of the normal singleton code goes here.  ... } return {  getInstance: function() {   if(!uniqueInstance) { // Instantiate only if the instance doesn't exist.    uniqueInstance = constructor();   }   return uniqueInstance;  } }})();

六、使用分支單例:
針對(duì)特定環(huán)境的代碼可以被包裝到分支型單例中,示例程序:

/* SimpleXhrFactory singleton, step 1. */var SimpleXhrFactory = (function() { // The three branches. var standard = {  createXhrObject: function() {   return new XMLHttpRequest();  } }; var activeXNew = {  createXhrObject: function() {   return new ActiveXObject('Msxml2.XMLHTTP');  } }; var activeXOld = {  createXhrObject: function() {   return new ActiveXObject('Microsoft.XMLHTTP');  } };})();/* SimpleXhrFactory singleton, step 2. */var SimpleXhrFactory = (function() { // The three branches. var standard = {  createXhrObject: function() {   return new XMLHttpRequest();  } }; var activeXNew = {  createXhrObject: function() {   return new ActiveXObject('Msxml2.XMLHTTP');  } }; var activeXOld = {  createXhrObject: function() {   return new ActiveXObject('Microsoft.XMLHTTP');  } }; // To assign the branch, try each method; return whatever doesn't fail. var testObject; try {  testObject = standard.createXhrObject();  return standard; // Return this if no error was thrown. } catch(e) {  try {   testObject = activeXNew.createXhrObject();   return activeXNew; // Return this if no error was thrown.  }  catch(e) {   try {    testObject = activeXOld.createXhrObject();    return activeXOld; // Return this if no error was thrown.   }   catch(e) {    throw new Error('No XHR object found in this environment.');   }  } }})();

發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 新余市| 得荣县| 喜德县| 开江县| 商都县| 古田县| 德格县| 贵南县| 永嘉县| 海城市| 定日县| 清水河县| 荔波县| 微山县| 西乌珠穆沁旗| 四子王旗| 武川县| 民权县| 淮南市| 汶上县| 澄城县| 庄浪县| 高唐县| 阜城县| 美姑县| 江华| 夏邑县| 犍为县| 张北县| 石棉县| 茶陵县| 凤山市| 东丽区| 建瓯市| 屏山县| 临武县| 临江市| 炎陵县| 莲花县| 井冈山市| 荣成市|