国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專(zhuān)欄INFORMATION COLUMN

JavaScript 設(shè)計(jì)模式讀書(shū)筆記(四)——單體模式和鏈?zhǔn)秸{(diào)用

DevWiki / 2506人閱讀

摘要:?jiǎn)误w模式在多種設(shè)計(jì)模式中,單體模式是最簡(jiǎn)單,也是最基礎(chǔ)的設(shè)計(jì)模式。和之前說(shuō)到的下劃線表示私用成員方法比較起來(lái),最大的優(yōu)點(diǎn)就是可以創(chuàng)建真正的私用成員,使其不會(huì)在構(gòu)造函數(shù)之外被隨意修改。

單體模式

在多種Javascript設(shè)計(jì)模式中,單體模式是最簡(jiǎn)單,也是最基礎(chǔ)的設(shè)計(jì)模式。它基礎(chǔ)到似乎不太像是一種設(shè)計(jì)模式,因?yàn)槲覀冊(cè)诰帉?xiě)代碼的過(guò)程中隨時(shí)都會(huì)用到,并不需要過(guò)多思考,這是它簡(jiǎn)單的一面。同時(shí),它不僅可以多帶帶存在,甚至也可以成為其他較高級(jí)設(shè)計(jì)模式的組成部分,這也是為什么說(shuō)它基礎(chǔ)的原因。

基本結(jié)構(gòu)

既然說(shuō)了單體模式是非常簡(jiǎn)單的,它的結(jié)構(gòu)也是很簡(jiǎn)單的。最簡(jiǎn)單的單體結(jié)構(gòu)實(shí)際上就是一個(gè)對(duì)象字面量:

var Singleton = {
  attribute1: true,
  attribute2: 1,

  method1: function() {
    ...
  },
  method2: function() {
    ...
  }
}

這就是一個(gè)基本的單體結(jié)構(gòu)了。

但是,不是任何對(duì)象字面量都可以被稱(chēng)作為單體結(jié)構(gòu)的,單體結(jié)構(gòu)應(yīng)該是一個(gè)只能被實(shí)例化一次,并且可以通過(guò)一個(gè)訪問(wèn)點(diǎn)訪問(wèn)的類(lèi)。所謂訪問(wèn)點(diǎn),可以理解為一個(gè)變量,這個(gè)變量在全局范圍內(nèi)可以訪問(wèn)到,并且只有一個(gè)。

單體結(jié)構(gòu)的作用

那么單體結(jié)構(gòu)的作用是什么呢,難道只是用來(lái)創(chuàng)建一個(gè)實(shí)例化的對(duì)象這么簡(jiǎn)單嗎?

命名空間
當(dāng)然不是的,單體最顯而易見(jiàn)的作用就是劃分命名空間。單體結(jié)構(gòu)在頁(yè)面中有一個(gè)訪問(wèn)點(diǎn),那么單體中保存的所有屬性和方法也就可以從這個(gè)訪問(wèn)點(diǎn)訪問(wèn)了,通過(guò)點(diǎn)運(yùn)算符的形式。而且也只有通過(guò)訪問(wèn)點(diǎn)才可以訪問(wèn)到。Javascript中的所有變量都是可以被改寫(xiě)的,當(dāng)一個(gè)程序員維護(hù)多個(gè)變量的時(shí)候,如果不將他們歸類(lèi)到命名空間中去的話,一旦變量被修改,查找起來(lái)將非常麻煩。同時(shí),一個(gè)命名良好的命名空間名稱(chēng)也可以提醒其他的程序員不要隨便修改其中的變量。

var Classicemi = {
  setName: function(name) {
    ...
  },
  // 其他方法
}

在其他地方訪問(wèn)setName方法的時(shí)候,一定要通過(guò)Classicemi.setName才能訪問(wèn)的到,這可以提醒其他程序員這個(gè)方法的作用和聲明的地點(diǎn)。通過(guò)命名空間將相似的方法組合到一起也可以增加代碼的文檔性。另一方面,網(wǎng)頁(yè)上的Javascript代碼會(huì)根據(jù)其用途有不同的劃分,分不同的人來(lái)維護(hù)。例如JS庫(kù)代碼,廣告代碼等。為了避免彼此之間產(chǎn)生沖突,在全局對(duì)象中也可以給不同用途的代碼劃分各自的命名空間,也就是存到各個(gè)單體中。

var Classicemi = {};

Classicemi.Common = {
  ...
};

Classicemi.ErrorCodes = {
  ...
};

網(wǎng)頁(yè)專(zhuān)用代碼包裝器
這是單體常見(jiàn)用法的一個(gè)示例。
在一個(gè)網(wǎng)站中,有些Javascript代碼是整個(gè)網(wǎng)站都要用到的,比如框架,庫(kù)等。而有些代碼是特定的網(wǎng)頁(yè)才會(huì)用到,例如對(duì)一個(gè)頁(yè)面中的DOM元素添加事件監(jiān)聽(tīng)等。一般我們會(huì)通過(guò)給頁(yè)面的load事件創(chuàng)建一個(gè)init方法來(lái)對(duì)所有需要的操作進(jìn)行初始化,將所有的初始化代碼放在一個(gè)方法中。
比如含有一個(gè)表單的頁(yè)面,我們要取消submit的默認(rèn)行為并添加ajax交互。

Classicemi.RegPage = {
  FORM_ID: "reg-form",
  OUTPUT_ID: "reg-results",

  // 表單處理方法
  handleSubmit: function(e) {
    e.preventDefult();
    ...
  } ,
  sendRegistration: function(data) {
    ... // 發(fā)送XHR請(qǐng)求
  },
  ...

  // 初始化方法
  init: function() {
    Classicemi.RegPage.formEl = $(Classicemi.RegPage.FORM_ID);
    Classicemi.RegPage.outputEl = $(Classicemi.RegPage.OUTPUT_ID);

    addEvent(Classicemi.RegPage.FormEl, "submit", Classicemi.RegPage.handleSubmit); // 添加事件
  }
};

// 頁(yè)面加載后運(yùn)行初始化方法
addLoadEvent(Classicemi.PageName.init);

這樣處理之后,對(duì)于不支持XHR的老式瀏覽器,可以按照原有方式發(fā)送表單數(shù)據(jù)并刷新頁(yè)面。而現(xiàn)代瀏覽器中則可以阻止表單提交的默認(rèn)行為,改由ajax對(duì)頁(yè)面進(jìn)行部分刷新,提供更好的用戶體驗(yàn)。

在單體中表示私用成員

對(duì)象中有時(shí)候有些屬性和方法是需要進(jìn)行保護(hù),避免被修改的,這些成員稱(chēng)為私用成員。在單體中聲明私用成員也是保護(hù)變量的一個(gè)好方法,另外,單體中創(chuàng)建私用成員的另一個(gè)好處在于由于單體只會(huì)被實(shí)例化一次,定義私用成員的時(shí)候就不用過(guò)多考慮內(nèi)存浪費(fèi)的問(wèn)題。

偽私用成員(下劃線表示法)
通過(guò)特殊命名的變量來(lái)提醒其他開(kāi)發(fā)者不要直接訪問(wèn)對(duì)象成員的方法。

Classicemi.Singleton = {
  // 私用成員
  _privateMethod: function() {
    ...
  },

  // 公開(kāi)成員
  publicMethod: function() {
    ...
  }
}

在該單體的方法中,可以通過(guò)this訪問(wèn)其他方法,但這會(huì)有一定的風(fēng)險(xiǎn),因?yàn)樵谔厥馇闆r下this不一定指向該單體。因此還是將調(diào)用名稱(chēng)寫(xiě)全是最安全的做法。

使用閉包
加下劃線的方法畢竟是假的,使用閉包才能創(chuàng)建真正意義上的私用成員。我們知道Javascript只存在函數(shù)作用域,因此要利用閉包的特性就不能使用對(duì)象字面量的形式,而要通過(guò)構(gòu)造函數(shù)返回來(lái)實(shí)現(xiàn)單體對(duì)象的創(chuàng)建了。第一步,我們通過(guò)一個(gè)構(gòu)造函數(shù)返回一個(gè)空對(duì)象,這就是單體對(duì)象的初始化:

var Classicemi.Singleton = (function() {
  return {};
})();

我們通過(guò)一個(gè)自執(zhí)行構(gòu)造函數(shù)返回單體對(duì)象的實(shí)例,下面就可以在這個(gè)構(gòu)造函數(shù)中添加我們需要的私用對(duì)象了。

var Classicemi.Singleton = (function() {
  // 私用屬性
  var privateAttribute = true;

  // 私用方法
  function privateMethod() {
    ...
  }
  return {};
})();

可以公開(kāi)訪問(wèn)的公開(kāi)屬性和方法可以寫(xiě)在構(gòu)造函數(shù)返回的對(duì)象中:

var Classicemi.Singleton = (function() {
  // 私用屬性
  var privateAttribute = true;

  // 私用方法
  function privateMethod() {
    ...
  }
  return {
    publicAttribute: false,

    publicMethod: function() {
      ...  
    }
  };
})();

這就是用閉包創(chuàng)建私有成員的方法,這種單體模式又被成為模塊模式(Module Pattern),我們創(chuàng)建的單體可以作為模塊,對(duì)代碼進(jìn)行組織,并劃分命名空間。

和之前說(shuō)到的下劃線表示私用成員方法比較起來(lái),最大的優(yōu)點(diǎn)就是可以創(chuàng)建真正的私用成員,使其不會(huì)在構(gòu)造函數(shù)之外被隨意修改。同時(shí),由于單體只會(huì)被實(shí)例化一次,不用擔(dān)心內(nèi)存浪費(fèi)的問(wèn)題。單體模式是Javascript中最簡(jiǎn)單,最流行的模式之一。

惰性實(shí)例化單體

單體一般會(huì)在頁(yè)面加載過(guò)程中進(jìn)行實(shí)例化,如果單體的體積比較大的話,可能會(huì)對(duì)加載速度造成影響。對(duì)于體積比較大,在頁(yè)面加載時(shí)也暫時(shí)不會(huì)起作用的單體,我們可以通過(guò)惰性加載(lazy loading)的方式進(jìn)行實(shí)例化,也就是在需要的時(shí)候再進(jìn)行實(shí)例化。

要實(shí)現(xiàn)惰性加載,我們要借助一個(gè)靜態(tài)方法來(lái)實(shí)現(xiàn)。在單體的命名空間中,我們聲明這樣一個(gè)方法getInstance()。這個(gè)方法會(huì)對(duì)單體是否已經(jīng)進(jìn)行了實(shí)例化進(jìn)行檢測(cè),如果還沒(méi)有實(shí)例,則會(huì)創(chuàng)建并返回實(shí)例。如果已經(jīng)實(shí)例化過(guò)了,則會(huì)返回現(xiàn)有實(shí)例。

實(shí)現(xiàn)惰性加載,我們要把原單體構(gòu)造函數(shù)中的所有成員轉(zhuǎn)移到一個(gè)內(nèi)部的新構(gòu)造函數(shù)中去:

Classicemi.Singleton = (function() {
  function constructor() {
    // 私用屬性
    var privateAttribute = true;

    // 私用方法
    function privateMethod() {
      ...
    }
    return {
      publicAttribute: false,

      publicMethod: function() {
        ...  
      }
    };
  }
})();

這個(gè)內(nèi)嵌構(gòu)造函數(shù)不能從閉包外部訪問(wèn),那么在閉包內(nèi)部返回對(duì)象中的getInstance方法可以有訪問(wèn)constructor方法的特權(quán),可以保證constructor方法只會(huì)被我們控制。

getInstance()方法內(nèi)部,首先要對(duì)單體是否已經(jīng)實(shí)例化進(jìn)行檢查,如果已經(jīng)實(shí)例化過(guò),就將其返回。如果沒(méi)有實(shí)例化,就調(diào)用constructor方法。我們需要一個(gè)變量來(lái)保存實(shí)例化后的單體。

Classicemi.Singleton = (function() {
  var uniqueInstance; // 保存實(shí)例化后的單體

  function constructor() {
    ...
  }

  return {
    getInstance: function() {
      if (!uniqueInstance) {
        uniqueInstance = constructor();
      }
      return uniqueInstance;
    }
  }
})();

單體的構(gòu)造函數(shù)像這樣被改寫(xiě)后,調(diào)用其方法的代碼就要由這樣:

Classicemi.Singleton.publicMethod();

改寫(xiě)為:

Classicemi.Singleton.getInstance().publicMethod();

惰性加載的使用可以避免不必要的單體在頁(yè)面加載時(shí)實(shí)例化影響加載速度,但引入一個(gè)getInstance()方法也會(huì)在一定程度上增加代碼的復(fù)雜性,因此惰性加載應(yīng)該在必要的時(shí)候再使用。

分支

分支(branching)技術(shù)的意義在于根據(jù)不同的條件,對(duì)單體進(jìn)行不同的實(shí)例化過(guò)程。

                    constructor
                         │condition
            ┌──────────────┼─────────────┐
            │            │            │
return   branch1      branch2      branch3

在構(gòu)造函數(shù)中存在不同的實(shí)例對(duì)象,針對(duì)condition判斷條件的不同返回值,構(gòu)造函數(shù)返回不同的對(duì)象作為單體的實(shí)例。例如對(duì)不同的瀏覽器來(lái)說(shuō),支持的XHR對(duì)象不一樣,大多數(shù)瀏覽器中是XMLHttpRequest的實(shí)例,早期的IE瀏覽器中是某種ActiveX的實(shí)例。我們?cè)趧?chuàng)建XHR對(duì)象的時(shí)候,可以根據(jù)不同瀏覽器的支持情況返回不同的實(shí)例,like this:

var XHRFactory = (function() {
  var standard = {
    createXHR: function() {
      return new XMLHttpRequest();
    }
  };
  var activeX = {
    createXHR: function() {
      return new ActiveXObject("Msxml2.XMLHTTP");
    }
  };
  var activeOld = {
    createXHR: function() {
      return new ActiveXObject("Microsofe.XMLHTTP");
    }
  }

  var testObj;
  try {
    testObj = standard.createXHR();
    return standard;
  } catch (e) {
    try {
      testObj = activeX.createXHR();
      return standard;
    } catch (e) {
      try {
        testObj = activeOld.createXHR();
        return standard;
      } catch (e) {
        throw new Error("No XHR object found in this environment.");
      }
    }
  }
})();

通過(guò)try-catch語(yǔ)句對(duì)瀏覽器XHR的支持性進(jìn)行測(cè)試同時(shí)防止拋出錯(cuò)誤,這樣不同瀏覽器都能創(chuàng)建出自己支持的XHR對(duì)象的實(shí)例。

單體模式之利弊 單體模式之利

單體模式能很好的組織代碼,由于單體對(duì)象只會(huì)實(shí)例化一次,單體對(duì)象中的代碼可以方便地進(jìn)行維護(hù)。

單體模式可以生成自己的命名空間,防止自己的代碼被別人隨意修改。

惰性實(shí)例化,有助于性能的提升。

分支,針對(duì)特定環(huán)境定制專(zhuān)屬的方法。

單體模式之弊

類(lèi)之間的耦合性可能增強(qiáng),因?yàn)橐ㄟ^(guò)命名空間去對(duì)一些方法進(jìn)行訪問(wèn),強(qiáng)耦合的后果會(huì)不利于單元測(cè)試。

鏈?zhǔn)秸{(diào)用

說(shuō)起鏈?zhǔn)秸{(diào)用,絕大多數(shù)的前端開(kāi)發(fā)者一定會(huì)馬上想到大名鼎鼎的jQuery,這說(shuō)明jQuery對(duì)開(kāi)發(fā)者思想的束縛還真是深啊。。。

Anyway,jQuery的鏈?zhǔn)秸{(diào)用特性確實(shí)是給開(kāi)發(fā)帶來(lái)了很多的便利,一條語(yǔ)句可以完成幾條語(yǔ)句的工作。那么鏈?zhǔn)秸{(diào)用是怎么實(shí)現(xiàn)的呢?

要實(shí)現(xiàn)鏈?zhǔn)秸{(diào)用其實(shí)是利用JavaScript的一些語(yǔ)法特性,主要分為兩個(gè)部分:
1. 創(chuàng)建包含需要操作的HTML元素的對(duì)象。
2. 對(duì)這個(gè)HTML元素進(jìn)行操作的方法。

將所有的方法都定義在構(gòu)造器函數(shù)prototype屬性所指的對(duì)象中,這樣所有的實(shí)例都可以調(diào)用這些方法,并且所有的方法都返回調(diào)用它們的實(shí)例的引用。這樣就實(shí)現(xiàn)了一個(gè)基本的鏈?zhǔn)秸{(diào)用。

(function() {
  function _$(els) {
    this.elements = [];
    ... // 通過(guò)一系列操作將匹配元素存入this.elements
  }

  window.$ = function() { // 對(duì)外接口
    return new _$(arguments);
  }
})();

接下來(lái)就可以在構(gòu)造器函數(shù)的原型所指對(duì)象中添加我們需要的方法了,我們可以根據(jù)需要添加DOM方法,ajax方法等,然后就可以完成一個(gè)小JS庫(kù)了~

(function() {
  function _$(els) {
    ...
  }

  _$.prototype = {
    each: function(fn) {
      for (var i = 0, len = this.length; i < len; i++) {
        fn.call(this, this.elements[i]);
      }
      return this;
    }
    ...
  }
})();

關(guān)鍵的一點(diǎn)就是每個(gè)方法的最后都是return this;,它返回調(diào)用方法的實(shí)例引用,這樣我們可以繼續(xù)讓這個(gè)this去調(diào)用其他方法,從而實(shí)現(xiàn)鏈?zhǔn)秸{(diào)用。

使用回調(diào)
回調(diào)的模式如果按照常規(guī)的方式運(yùn)用在一些取值器方法上的時(shí)候,可能會(huì)給使用者造成一些麻煩。因?yàn)槭褂萌≈灯鞯臅r(shí)候,可能下一步我們需要對(duì)取到的值進(jìn)行一些操作,而鏈?zhǔn)秸{(diào)用返回的是對(duì)象本身。

為了保持鏈?zhǔn)秸{(diào)用能使用,return this;是不能動(dòng)的,那么要對(duì)取到的值進(jìn)行操作的話,就應(yīng)該在取值器內(nèi)部進(jìn)行,將我們需要的操作過(guò)程封裝成函數(shù)傳入取值器,將值作為自定義函數(shù)的參數(shù),這就是典型的回調(diào)函數(shù)思想。

(function() {
  function _$(els) {
    ...
  }

  _$.prototype = {
    getValue: function(callback) {
      callback.call(this, this.value); // 通過(guò)傳入回調(diào)函數(shù)對(duì)取到的值進(jìn)行操作
      return this; // 同時(shí)不影響繼續(xù)鏈?zhǔn)秸{(diào)用
    }
    ...
  }
})();

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/78066.html

相關(guān)文章

  • 筆記】 你不知道的JS讀書(shū)筆記——異步

    摘要:異步請(qǐng)求線程在在連接后是通過(guò)瀏覽器新開(kāi)一個(gè)線程請(qǐng)求將檢測(cè)到狀態(tài)變更時(shí),如果設(shè)置有回調(diào)函數(shù),異步線程就產(chǎn)生狀態(tài)變更事件,將這個(gè)回調(diào)再放入事件循環(huán)隊(duì)列中。 基礎(chǔ):瀏覽器 -- 多進(jìn)程,每個(gè)tab頁(yè)獨(dú)立一個(gè)瀏覽器渲染進(jìn)程(瀏覽器內(nèi)核) 每個(gè)瀏覽器渲染進(jìn)程是多線程的,主要包括:GUI渲染線程 JS引擎線程 也稱(chēng)為JS內(nèi)核,負(fù)責(zé)處理Javascript腳本程序。(例如V8引擎) JS引擎線程負(fù)...

    junnplus 評(píng)論0 收藏0
  • JavaScript 語(yǔ)言精粹》讀書(shū)筆記 - 函數(shù)

    摘要:語(yǔ)言精粹讀書(shū)筆記第四章函數(shù)函數(shù)字面量函數(shù)字面量包含個(gè)部分第一部分,保留字第二部分,函數(shù)名,它可以被忽略。這個(gè)超級(jí)延遲綁定使得函數(shù)對(duì)高度復(fù)用。構(gòu)造器調(diào)用模式一個(gè)函數(shù),如果創(chuàng)建的目的就是希望結(jié)合的前綴來(lái)調(diào)用,那它就被稱(chēng)為構(gòu)造器構(gòu)造。 《JavaScript 語(yǔ)言精粹》 讀書(shū)筆記 第四章 函數(shù) Functions 函數(shù)字面量 函數(shù)字面量包含4個(gè)部分: 第一部分, 保留字 function...

    wdzgege 評(píng)論0 收藏0
  • 筆記】你不知道的JS讀書(shū)筆記——Promise

    摘要:寫(xiě)在前面這一章的順序?qū)τ谖唇佑|過(guò)使用過(guò)的童鞋而言略抽象了,前邊幾章主要為了說(shuō)明和之前的異步方式相比有什么優(yōu)勢(shì)和它能解決什么問(wèn)題,后邊才詳解的設(shè)計(jì)和各種場(chǎng)景下如何使用。建議先了解和簡(jiǎn)單使用過(guò)后再閱讀,效果更佳。 寫(xiě)在前面:Promise這一章的順序?qū)τ谖唇佑|過(guò)使用過(guò)Promise的童鞋而言略抽象了,前邊幾章主要為了說(shuō)明Promise和之前的異步方式相比有什么優(yōu)勢(shì)和它能解決什么問(wèn)題,后邊才...

    mumumu 評(píng)論0 收藏0
  • 《微服務(wù)設(shè)計(jì)讀書(shū)筆記(關(guān)于微服務(wù)的一點(diǎn)想法)

    摘要:而微服務(wù)將這個(gè)理念應(yīng)用在獨(dú)立的服務(wù)上。微服務(wù)對(duì)比與原來(lái)的單體應(yīng)用,有它的優(yōu)勢(shì),如服務(wù)的自治性增強(qiáng)但同時(shí)也會(huì)帶來(lái)一些其他問(wèn)題,如性能復(fù)雜度等問(wèn)題。想要使用微服務(wù),首先是要清楚哪些業(yè)務(wù)或者功能應(yīng)該成為單獨(dú)的服務(wù)。其次,考慮業(yè)務(wù)極有可能的變化。 1、在學(xué)習(xí)軟件構(gòu)造、設(shè)計(jì)相關(guān)知識(shí)時(shí),大家應(yīng)該有學(xué)習(xí)到內(nèi)聚性的概念:即把因相同原因而變化的東西聚合到一起,而把因不同原因而變化的東西分離開(kāi)來(lái)。而 微服...

    lpjustdoit 評(píng)論0 收藏0
  • CSS技巧

    摘要:技巧使你的更加專(zhuān)業(yè)這是上關(guān)于技巧的一篇譯文,另外你也可以在本項(xiàng)目看到原文。列舉了一些很實(shí)用的技巧,比如給空內(nèi)容的標(biāo)簽添加內(nèi)容,逗號(hào)分隔列表等等。排序算法看源碼,把它背下來(lái)吧排序算法的封裝。主要幫助初學(xué)者更好的掌握排序算法的實(shí)現(xiàn)。 成為專(zhuān)業(yè)程序員路上用到的各種優(yōu)秀資料、神器及框架 成為一名專(zhuān)業(yè)程序員的道路上,需要堅(jiān)持練習(xí)、學(xué)習(xí)與積累,技術(shù)方面既要有一定的廣度,更要有自己的深度。 Java...

    DangoSky 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<