真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

如何封裝代碼

本篇內(nèi)容介紹了“如何封裝代碼”的有關(guān)知識,在實(shí)際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!

為彭山等地區(qū)用戶提供了全套網(wǎng)頁設(shè)計制作服務(wù),及彭山網(wǎng)站建設(shè)行業(yè)解決方案。主營業(yè)務(wù)為網(wǎng)站設(shè)計制作、成都網(wǎng)站制作、彭山網(wǎng)站設(shè)計,以傳統(tǒng)方式定制建設(shè)網(wǎng)站,并提供域名空間備案等一條龍服務(wù),秉承以專業(yè)、用心的態(tài)度為用戶提供真誠的服務(wù)。我們深信只要達(dá)到每一位用戶的要求,就會得到認(rèn)可,從而選擇與我們長期合作。這樣,我們也可以走得更遠(yuǎn)!

為什么要封裝代碼?

我們經(jīng)常聽說:“寫代碼要有良好的封裝,要高內(nèi)聚,低耦合”。那怎樣才算良好的封裝,我們?yōu)槭裁匆庋b呢?其實(shí)封裝有這樣幾個好處:

  1.   封裝好的代碼,內(nèi)部變量不會污染外部。

  2.   可以作為一個模塊給外部調(diào)用。外部調(diào)用者不需要知道實(shí)現(xiàn)的細(xì)節(jié),只需要按照約定的規(guī)范使用就行了。

  3.   對擴(kuò)展開放,對修改關(guān)閉,即開閉原則。外部不能修改模塊,既保證了模塊內(nèi)部的正確性,又可以留出擴(kuò)展接口,使用靈活。

怎么封裝代碼?

JS生態(tài)已經(jīng)有很多模塊了,有些模塊封裝得非常好,我們使用起來很方便,比如jQuery,Vue等。如果我們仔細(xì)去看這些模塊的源碼,我們會發(fā)現(xiàn)他們的封裝都是有規(guī)律可循的。這些規(guī)律總結(jié)起來就是設(shè)計模式,用于代碼封裝的設(shè)計模式主要有工廠模式,創(chuàng)建者模式,單例模式,原型模式四種。下面我們結(jié)合一些框架源碼來看看這四種設(shè)計模式:

工廠模式

工廠模式的名字就很直白,封裝的模塊就像一個工廠一樣批量的產(chǎn)出需要的對象。常見工廠模式的一個特征就是調(diào)用的時候不需要使用new,而且傳入的參數(shù)比較簡單。但是調(diào)用次數(shù)可能比較頻繁,經(jīng)常需要產(chǎn)出不同的對象,頻繁調(diào)用時不用new也方便很多。一個工廠模式的代碼結(jié)構(gòu)如下所示:

function factory(type) {    switch(type) {      case 'type1':        return new Type1();      case 'type2':        return new Type2();      case 'type3':        return new Type3();    }  }

上述代碼中,我們傳入了type,然后工廠根據(jù)不同的type來創(chuàng)建不同的對象。

實(shí)例: 彈窗組件

下面來看看用工廠模式的例子,假如我們有如下需求:

我們項目需要一個彈窗,彈窗有幾種:消息型彈窗,確認(rèn)型彈窗,取消型彈窗,他們的顏色和內(nèi)容可能是不一樣的。

針對這幾種彈窗,我們先來分別建一個類:

function infoPopup(content, color) {}  function confirmPopup(content, color) {}  function cancelPopup(content, color) {}

如果我們直接使用這幾個類,就是這樣的:

let infoPopup1 = new infoPopup(content, color);  let infoPopup2 = new infoPopup(content, color);  let confirmPopup1 = new confirmPopup(content, color);  ...

每次用的時候都要去new對應(yīng)的彈窗類,我們用工廠模式改造下,就是這樣:

// 新加一個方法popup把這幾個類都包裝起來  function popup(type, content, color) {    switch(type) {      case 'infoPopup':        return new infoPopup(content, color);      case 'confirmPopup':        return new confirmPopup(content, color);      case 'cancelPopup':        return new cancelPopup(content, color);    }  }

然后我們使用popup就不用new了,直接調(diào)用函數(shù)就行:

let infoPopup1 = popup('infoPopup', content, color);

改造成面向?qū)ο?/strong>

上述代碼雖然實(shí)現(xiàn)了工廠模式,但是switch始終感覺不是很優(yōu)雅。我們使用面向?qū)ο蟾脑煜聀opup,將它改為一個類,將不同類型的彈窗掛載在這個類上成為工廠方法:

function popup(type, content, color) {    // 如果是通過new調(diào)用的,返回對應(yīng)類型的彈窗    if(this instanceof popup) {      return new this[type](content, color);    } else {      // 如果不是new調(diào)用的,使用new調(diào)用,會走到上面那行代碼      return new popup(type, content, color);    }  }  // 各種類型的彈窗全部掛載在原型上成為實(shí)例方法  popup.prototype.infoPopup = function(content, color) {}  popup.prototype.confirmPopup = function(content, color) {}  popup.prototype.cancelPopup = function(content, color) {}

封裝成模塊

這個popup不僅僅讓我們調(diào)用的時候少了一個new,他其實(shí)還把相關(guān)的各種彈窗都封裝在了里面,這個popup可以直接作為模塊export出去給別人調(diào)用,也可以掛載在window上作為一個模塊給別人調(diào)用。因?yàn)閜opup封裝了彈窗的各種細(xì)節(jié),即使以后popup內(nèi)部改了,或者新增了彈窗類型,或者彈窗類的名字變了,只要保證對外的接口參數(shù)不變,對外面都沒有影響。掛載在window上作為模塊可以使用自執(zhí)行函數(shù):

(function(){       function popup(type, content, color) {      if(this instanceof popup) {        return new this[type](content, color);      } else {        return new popup(type, content, color);      }    }    popup.prototype.infoPopup = function(content, color) {}    popup.prototype.confirmPopup = function(content, color) {}    popup.prototype.cancelPopup = function(content, color) {}   window.popup = popup;  })()  // 外面就直接可以使用popup模塊了  let infoPopup1 = popup('infoPopup', content, color);

jQuery的工廠模式

jQuery也是一個典型的工廠模式,你給他一個參數(shù),他就給你返回符合參數(shù)DOM對象。那jQuery這種不用new的工廠模式是怎么實(shí)現(xiàn)的呢?其實(shí)就是jQuery內(nèi)部幫你調(diào)用了new而已,jQuery的調(diào)用流程簡化了就是這樣:

(function(){    var jQuery = function(selector) {      return new jQuery.fn.init(selector);   // new一下init, init才是真正的構(gòu)造函數(shù)    }    jQueryjQuery.fn = jQuery.prototype;     // jQuery.fn就是jQuery.prototype的簡寫    jQuery.fn.init = function(selector) {      // 這里面實(shí)現(xiàn)真正的構(gòu)造函數(shù)    }    // 讓init和jQuery的原型指向同一個對象,便于掛載實(shí)例方法    jQueryjQuery.fn.init.prototype = jQuery.fn;     // 最后將jQuery掛載到window上    window.$ = window.jQuery = jQuery;  })();

上述代碼結(jié)構(gòu)來自于jQuery源碼,從中可以看出,你調(diào)用時省略的new在jQuery里面幫你調(diào)用了,目的是為了使大量調(diào)用更方便。但是這種結(jié)構(gòu)需要借助一個init方法,最后還要將jQuery和init的原型綁在一起,其實(shí)還有一種更加簡便的方法可以實(shí)現(xiàn)這個需求:

var jQuery = function(selector) {    if(!(this instanceof jQuery)) {      return new jQuery(selector);    }    // 下面進(jìn)行真正構(gòu)造函數(shù)的執(zhí)行  }

上述代碼就簡潔多了,也可以實(shí)現(xiàn)不用new直接調(diào)用,這里利用的特性是this在函數(shù)被new調(diào)用時,指向的是new出來的對象,new出來的對象自然是類的instance,這里的this instanceof jQuery就是true。如果是普通調(diào)用,他就是false,我們就幫他new一下。

建造者模式

建造者模式是用于比較復(fù)雜的大對象的構(gòu)建,比如Vue,Vue內(nèi)部包含一個功能強(qiáng)大,邏輯復(fù)雜的對象,在構(gòu)建的時候也需要傳很多參數(shù)進(jìn)去。像這種需要創(chuàng)建的情況不多,創(chuàng)建的對象本身又很復(fù)雜的時候就適用建造者模式。建造者模式的一般結(jié)構(gòu)如下:

function Model1() {}   // 模塊1  function Model2() {}   // 模塊2  // 最終使用的類  function Final() {    this.model1 = new Model1();    this.model2 = new Model2();  }  // 使用時  var obj = new Final();

上述代碼中我們最終使用的是Final,但是Final里面的結(jié)構(gòu)比較復(fù)雜,有很多個子模塊,F(xiàn)inal就是將這些子模塊組合起來完成功能,這種需要精細(xì)化構(gòu)造的就適用于建造者模式。

實(shí)例:編輯器插件

假設(shè)我們有這樣一個需求:

寫一個編輯器插件,初始化的時候需要配置大量參數(shù),而且內(nèi)部的功能很多很復(fù)雜,可以改變字體顏色和大小,也可以前進(jìn)后退。

一般一個頁面就只有一個編輯器,而且里面的功能可能很復(fù)雜,可能需要調(diào)整顏色,字體等。也就是說這個插件內(nèi)部可能還會調(diào)用其他類,然后將他們組合起來實(shí)現(xiàn)功能,這就適合建造者模式。我們來分析下做這樣一個編輯器需要哪些模塊:

  1.   編輯器本身肯定需要一個類,是給外部調(diào)用的接口

  2.   需要一個控制參數(shù)初始化和頁面渲染的類

  3.   需要一個控制字體的類

  4.   需要一個狀態(tài)管理的類 

// 編輯器本身,對外暴露  function Editor() {    // 編輯器里面就是將各個模塊組合起來實(shí)現(xiàn)功能    this.initer = new HtmlInit();    this.fontController = new FontController();    this.stateController = new StateController(this.fontController);  }  // 初始化參數(shù),渲染頁面  function HtmlInit() {  }  HtmlInit.prototype.initStyle = function() {}     // 初始化樣式  HtmlInit.prototype.renderDom = function() {}     // 渲染DOM  // 字體控制器  function FontController() {  }  FontController.prototype.changeFontColor = function() {}    // 改變字體顏色  FontController.prototype.changeFontSize = function() {}     // 改變字體大小  // 狀態(tài)控制器  function StateController(fontController) {    this.states = [];       // 一個數(shù)組,存儲所有狀態(tài)    this.currentState = 0;  // 一個指針,指向當(dāng)前狀態(tài)    this.fontController = fontController;    // 將字體管理器注入,便于改變狀態(tài)的時候改變字體  }  StateController.prototype.saveState = function() {}     // 保存狀態(tài)  StateController.prototype.backState = function() {}     // 后退狀態(tài)  StateController.prototype.forwardState = function() {}     // 前進(jìn)狀態(tài)

上面的代碼其實(shí)就將一個編輯器插件的架子搭起來了,具體實(shí)現(xiàn)功能就是往這些方法里面填入具體的內(nèi)容就行了,其實(shí)就是各個模塊的相互調(diào)用,比如我們要實(shí)現(xiàn)后退狀態(tài)的功能就可以這樣寫:

StateController.prototype.backState = function() {    var state = this.states[this.currentState - 1];  // 取出上一個狀態(tài)    this.fontController.changeFontColor(state.color);  // 改回上次顏色    this.fontController.changeFontSize(state.size);    // 改回上次大小  }

單例模式

單例模式適用于全局只能有一個實(shí)例對象的場景,單例模式的一般結(jié)構(gòu)如下:

function Singleton() {}  Singleton.getInstance = function() {    if(this.instance) {      return this.instance;    }    this.instance = new Singleton();    return this.instance;  }

上述代碼中,Singleton類掛載了一個靜態(tài)方法getInstance,如果要獲取實(shí)例對象只能通過這個方法拿,這個方法會檢測是不是有現(xiàn)存的實(shí)例對象,如果有就返回,沒有就新建一個。

實(shí)例:全局?jǐn)?shù)據(jù)存儲對象

假如我們現(xiàn)在有這樣一個需求:

我們需要對一個全局的數(shù)據(jù)對象進(jìn)行管理,這個對象只能有一個,如果有多個會導(dǎo)致數(shù)據(jù)不同步。

這個需求要求全局只有一個數(shù)據(jù)存儲對象,是典型的適合單例模式的場景,我們可以直接套用上面的代碼模板,但是上面的代碼模板獲取instance必須要調(diào)getInstance才行,要是某個使用者直接調(diào)了Singleton()或者new Singleton()就會出問題,這次我們換一種寫法,讓他能夠兼容Singleton()和new Singleton(),使用起來更加傻瓜化:

function store() {    if(store.instance) {      return store.instance;    }    store.instance = this;  }

上述代碼支持使用new store()的方式調(diào)用,我們使用了一個靜態(tài)變量instance來記錄是否有進(jìn)行過實(shí)例化,如果實(shí)例化了就返回這個實(shí)例,如果沒有實(shí)例化說明是第一次調(diào)用,那就把this賦給這個這個靜態(tài)變量,因?yàn)槭鞘褂胣ew調(diào)用,這時候的this指向的就是實(shí)例化出來的對象,并且最后會隱式的返回this。

如果我們還想支持store()直接調(diào)用,我們可以用前面工廠模式用過的方法,檢測this是不是當(dāng)前類的實(shí)例,如果不是就幫他用new調(diào)用就行了:

function store() {    // 加一個instanceof檢測    if(!(this instanceof store)) {      return new store();    }     // 下面跟前面一樣的    if(store.instance) {      return store.instance;    }    store.instance = this;  }

然后我們用兩種方式調(diào)用來檢測下:

如何封裝代碼

實(shí)例:vue-router

vue-router其實(shí)也用到了單例模式,因?yàn)槿绻粋€頁面有多個路由對象,可能造成狀態(tài)的沖突,vue-router的單例實(shí)現(xiàn)方式又有點(diǎn)不一樣,下列代碼來自vue-router源碼:

let _Vue;  function install(Vue) {    if (install.installed && _Vue === Vue) return;    install.installed = true    _Vue = Vue  }

每次我們調(diào)用vue.use(vueRouter)的時候其實(shí)都會去執(zhí)行vue-router模塊的install方法,如果用戶不小心多次調(diào)用了vue.use(vueRouter)就會造成install的多次執(zhí)行,從而產(chǎn)生不對的結(jié)果。vue-router的install在第一次執(zhí)行時,將installed屬性寫成了true,并且記錄了當(dāng)前的Vue,這樣后面在同一個Vue里面再次執(zhí)行install就會直接return了,這也是一種單例模式。

可以看到我們這里三種代碼都是單例模式,他們雖然形式不一樣,但是核心思想都是一樣的,都是用一個變量來標(biāo)記代碼是否已經(jīng)執(zhí)行過了,如果執(zhí)行過了就返回上次的執(zhí)行結(jié)果,這樣就保證了多次調(diào)用也會拿到一樣的結(jié)果。

原型模式

原型模式最典型的應(yīng)用就是JS本身啊,JS的原型鏈就是原型模式。JS中可以使用Object.create指定一個對象作為原型來創(chuàng)建對象:

const obj = {    x: 1,    func: () => {}  }  // 以obj為原型創(chuàng)建一個新對象  const newObj = Object.create(obj);  console.log(newObj.__proto__ === obj);    // true  console.log(newObj.x);    // 1

上述代碼我們將obj作為原型,然后用Object.create創(chuàng)建的新對象都會擁有這個對象上的屬性和方法,這其實(shí)就算是一種原型模式。還有JS的面向?qū)ο笃鋵?shí)更加是這種模式的體現(xiàn),比如JS的繼承可以這樣寫:

function Parent() {    this.parentAge = 50;  }  function Child() {}  Child.prototype = new Parent();  ChildChild.prototype.constructor = Child;      // 注意重置constructor  const obj = new Child();  console.log(obj.parentAge);    // 50

這里的繼承其實(shí)就是讓子類Child.prototype.__proto__的指向父類的prototype,從而獲取父類的方法和屬性。

“如何封裝代碼”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識可以關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!


分享題目:如何封裝代碼
當(dāng)前地址:http://weahome.cn/article/giiddh.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部