1、JS封裝就是盡量把使用的方式簡(jiǎn)單化,內(nèi)部邏輯和使用解耦。通俗的說就是使用的時(shí)候只需要知道參數(shù)和返回值,其他條件盡量不要使用人員進(jìn)行設(shè)置。

創(chuàng)新互聯(lián)公司是一家專注于成都網(wǎng)站設(shè)計(jì)、網(wǎng)站建設(shè)與策劃設(shè)計(jì),荔波網(wǎng)站建設(shè)哪家好?創(chuàng)新互聯(lián)公司做網(wǎng)站,專注于網(wǎng)站建設(shè)十多年,網(wǎng)設(shè)計(jì)領(lǐng)域的專業(yè)建站公司;建站業(yè)務(wù)涵蓋:荔波等地區(qū)。荔波做網(wǎng)站價(jià)格咨詢:18982081108
2、JS封裝的方法有函數(shù)方式、對(duì)象的方式、閉包的方式。
舉例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
1)函數(shù)方式
function kk(a,b){
內(nèi)部對(duì)a,b怎么處理就不需要關(guān)心了
}
2)對(duì)象方式
function kk(a,b){
this.x = a;
this.y = b;
}
var k = new kk(1,2);//通過面向?qū)ο蟮姆绞?/p>
alert(k.x);
3)閉包方式
function kk(a,b){
var k = 1;
return function tt(){
k++;
}
}
var u = kk(1,2);
u();//閉包實(shí)現(xiàn)累加
u();//閉包實(shí)現(xiàn)累加
以下為CSDN編譯:地板上堆放的衣服首先,我們來看看angular-seed,它是AngularJS應(yīng)用開發(fā)的官方入門項(xiàng)目,其文件結(jié)構(gòu)是這樣的:css/img/js/app.jscontrollers.jsdirectives.jsfilters.jsservices.jslib/partials/看起來就像是把衣服按類型堆在地板上,一堆襪子、一堆內(nèi)衣、一堆襯衫等等。你知道拐角的那堆襪子里有今天要穿的黑色羊毛襪,但你仍需要花上一段時(shí)間來尋找。這種組織方式很凌亂。一旦你的代碼中存在6、7個(gè)甚至更多的控制器或者服務(wù),文件管理就會(huì)變得難以處理:很難找到想要尋找的對(duì)象,源代碼控制中的文件也變更集變得難懂。襪子抽屜常見的JavaScript文件結(jié)構(gòu)還有另一種形式,即按原型將文件分類。我們繼續(xù)用整理衣服來比喻:現(xiàn)在我們買了有很多抽屜的衣柜,打算將襪子放在其中一個(gè)抽屜里,內(nèi)衣放在另一個(gè)抽屜,再把襯衫整齊地疊在第三個(gè)抽屜……想象一下,我們正在開發(fā)一個(gè)簡(jiǎn)單的電子商務(wù)網(wǎng)站,包括登陸流程、產(chǎn)品目錄以及購物車UI。同樣,我們將文件分為以下幾個(gè)原型:models(業(yè)務(wù)邏輯和狀態(tài))、controllers以及services(HTTP/JSON端點(diǎn)加密),而按照Angular默認(rèn)那樣非籠統(tǒng)地歸到“service”架構(gòu)。因此我們的JavaScript目錄變成了這樣:controllers/LoginController.jsRegistrationController.jsProductDetailController.jsSearchResultsController.jsdirectives.jsfilters.jsmodels/CartModel.jsProductModel.jsSearchResultsModel.jsUserModel.jsservices/CartService.jsUserService.jsProductService.js不錯(cuò),現(xiàn)在已經(jīng)可以通過樹形文件目錄或者IDE快捷鍵更方便地查找文件了,源代碼控制中的變更集(changeset)也能夠清楚地描述文件修改記錄。雖然已經(jīng)獲得了極大的改進(jìn),但是仍有一定的局限性。想象一下,你現(xiàn)在正在辦公室,突然發(fā)現(xiàn)明天有個(gè)商務(wù)出差,需要幾套干洗的衣服,因此給家里打電話告訴另一半把黑色和藍(lán)色的西裝交給清潔工,還有黑紋領(lǐng)帶配灰色襯衫、白襯衫配純黃領(lǐng)帶。如果你的另一半并不熟悉衣柜,又該如何從三條黃色的領(lǐng)帶中挑出你的正確需求?模塊化希望衣服的比喻沒有讓你覺得過于陳舊,下面舉一個(gè)實(shí)例:你的搭檔是新來的開發(fā)者,他被要求去修補(bǔ)這個(gè)復(fù)雜應(yīng)用中的一處bug。他掃過這些文件夾,看到了controllers、models、services等文件夾整齊地排列著,但是他仍然不清楚對(duì)象間的依賴關(guān)系。處于某些原因,他希望能夠重用部分代碼,這需要從各個(gè)文件夾中搜集相關(guān)文件,而且常常會(huì)遺漏某些文件夾中的對(duì)象。信或不信,你確實(shí)很少會(huì)在新項(xiàng)目中重用很多代碼,但你很可能需要重用登陸系統(tǒng)這樣的整個(gè)模塊。所以,是不是按功能劃分文件會(huì)更好?下面的文件結(jié)構(gòu)是以功能劃分后的應(yīng)用結(jié)構(gòu):cart/CartModel.jsCartService.jscommon/directives.jsfilters.jsproduct/search/SearchResultsController.jsSearchResultsModel.jsProductDetailController.jsProductModel.jsProductService.jsuser/LoginController.jsRegistrationController.jsUserModel.jsUserService.js雖然現(xiàn)實(shí)世界中有空間限制,難以隨意整理服裝,但是編程中類似的處理卻是零成本的。現(xiàn)在即使是新來的開發(fā)者也能通過頂級(jí)文件夾的命名理解應(yīng)用的功能,相同文件夾下的文件會(huì)存在互相依賴等關(guān)系,而且僅僅通過瀏覽文件組織結(jié)構(gòu)就能輕易理解登錄、注冊(cè)等功能的原理。新的項(xiàng)目也可以通過復(fù)制粘貼來重用其中的代碼了。使用AngularJS我們可以進(jìn)一步將相關(guān)代碼組織為模塊:var userModule = angular.module('userModule',[]); userModule.factory('userService', ['$http', function($http) { return new UserService($http); }]); userModule.factory('userModel', ['userService', function(userService) { return new UserModel(userService); }]); userModule.controller('loginController', ['$scope', 'userModel', LoginController]); userModule.controller('registrationController', ['$scope', 'userModel', RegistrationController]);如果我們將UserModule.js文件放到user文件夾,它就成了這個(gè)模塊中使用到的對(duì)象的“manifest”,這也是適合RequireJS或者Browserify中放置某些加載指令的地方如何處理通用代碼每個(gè)應(yīng)用都會(huì)有某些代碼廣泛使用在多個(gè)模塊中,我們常常使用名為“commom”或者“shared”的文件夾來存放這些功能代碼。又該如何處理這些通用代碼呢?如果模塊中的對(duì)象需要直接訪問幾個(gè)“通用”對(duì)象,為這些對(duì)象提供幾個(gè)Facade(外觀模式)。這有助于減少每個(gè)對(duì)象的依賴者,而過多的關(guān)聯(lián)對(duì)象通常意味著糟糕的代碼結(jié)構(gòu)。如果“通用”模塊變得過于龐大,你需要將它按功能領(lǐng)域細(xì)分為多個(gè)子模塊。確保每個(gè)應(yīng)用模塊只使用它需要的“通用”模塊,這即是SOLID中“接口隔離原則”的變種。在根范圍($rootScope)添加實(shí)體,這樣子范圍也可以使用,適合多個(gè)控制器都依賴同一個(gè)對(duì)象(比如“PermissionsModel”)的情況。在解耦兩個(gè)不明確互相引用的組件時(shí),請(qǐng)使用事件。Angular中Scope對(duì)象的$emit、$broadcast以及$on方法使得這種方式變得現(xiàn)實(shí)。控制器能夠觸發(fā)一個(gè)事件來執(zhí)行某些動(dòng)作,然后再動(dòng)作結(jié)束后收到相應(yīng)地通知。
責(zé)任鏈模式
什么是責(zé)任鏈模式
責(zé)任鏈(Chain of Responsibility)模式的定義:為了避免請(qǐng)求發(fā)送者與多個(gè)請(qǐng)求處理者耦合在一起,將所有請(qǐng)求的處理者通過前一對(duì)象記住其下一個(gè)對(duì)象的引用而連成一條鏈;當(dāng)有請(qǐng)求發(fā)生時(shí),可將請(qǐng)求沿著這條鏈傳遞,直到有對(duì)象處理它為止。(此處引自 gof 設(shè)計(jì)模式)
在責(zé)任鏈模式中,客戶只需要將請(qǐng)求發(fā)送到責(zé)任鏈上即可,無須關(guān)心請(qǐng)求的處理細(xì)節(jié)和請(qǐng)求的傳遞過程,所以責(zé)任鏈將請(qǐng)求的發(fā)送者和請(qǐng)求的處理者解耦了。
責(zé)任鏈模式是一種對(duì)象行為型模式,其主要優(yōu)點(diǎn)如下:
1.降低了對(duì)象之間的耦合度。該模式使得一個(gè)對(duì)象無須知道到底是哪一個(gè)對(duì)象處理其請(qǐng)求以及鏈的結(jié)構(gòu),發(fā)送者和接收者也無須擁有對(duì)方的明確信息。
2.增強(qiáng)了系統(tǒng)的可擴(kuò)展性。可以根據(jù)需要增加新的請(qǐng)求處理類,滿足開閉原則。
3.增強(qiáng)了給對(duì)象指派職責(zé)的靈活性。當(dāng)工作流程發(fā)生變化,可以動(dòng)態(tài)地改變鏈內(nèi)的成員或者調(diào)動(dòng)它們的次序,也可動(dòng)態(tài)地新增或者刪除責(zé)任。
4.責(zé)任鏈簡(jiǎn)化了對(duì)象之間的連接。每個(gè)對(duì)象只需保持一個(gè)指向其后繼者的引用,不需保持其他所有處理者的引用,這避免了使用眾多的 if 或者 if···else 語句。
5.責(zé)任分擔(dān)。每個(gè)類只需要處理自己該處理的工作,不該處理的傳遞給下一個(gè)對(duì)象完成,明確各類的責(zé)任范圍,符合類的單一職責(zé)原則。
其主要缺點(diǎn)如下。
1.不能保證每個(gè)請(qǐng)求一定被處理。由于一個(gè)請(qǐng)求沒有明確的接收者,所以不能保證它一定會(huì)被處理,該請(qǐng)求可能一直傳到鏈的末端都得不到處理。
2.對(duì)比較長的職責(zé)鏈,請(qǐng)求的處理可能涉及多個(gè)處理對(duì)象,系統(tǒng)性能將受到一定影響。
3.職責(zé)鏈建立的合理性要靠客戶端來保證,增加了客戶端的復(fù)雜性,可能會(huì)由于職責(zé)鏈的錯(cuò)誤設(shè)置而導(dǎo)致系統(tǒng)出錯(cuò),如可能會(huì)造成循環(huán)調(diào)用。
其他說明
責(zé)任鏈模式,總的一個(gè)核心就是請(qǐng)求者不必知道是誰哪個(gè)節(jié)點(diǎn)對(duì)象處理的請(qǐng)求,由于處理請(qǐng)求的可以在不同對(duì)象下處理,所以請(qǐng)求者跟接受者是解耦的。
純的責(zé)任鏈:要求請(qǐng)求在這些對(duì)象鏈中 必須被處理 ,而且一個(gè)節(jié)點(diǎn)處理對(duì)象,要么只處理請(qǐng)求,要么把請(qǐng)求轉(zhuǎn)發(fā)給下個(gè)節(jié)點(diǎn)對(duì)象處理;
不純的責(zé)任鏈:要求在責(zé)任鏈里 **不一定會(huì)有處理結(jié)構(gòu) **,而且一個(gè)節(jié)點(diǎn)對(duì)象,即可以處理部分請(qǐng)求,并把請(qǐng)求再轉(zhuǎn)發(fā)下個(gè)節(jié)點(diǎn)處理;
javascript 中介者模式
責(zé)任鏈模式對(duì)前端開發(fā)來說可能有點(diǎn)陌生,但是看了前面的描述又感覺似曾相識(shí)
實(shí)際上 express、redux 里的 middleware 都可以簡(jiǎn)單理解為責(zé)任鏈模式的運(yùn)用
要實(shí)現(xiàn)中間件模式,最重要的實(shí)現(xiàn)細(xì)節(jié)是:
1.可以通過調(diào)用 use() 函數(shù)來注冊(cè)新的中間件
2.當(dāng)接收到需要處理的新數(shù)據(jù)時(shí),注冊(cè)的中間件在執(zhí)行流程中被依次調(diào)用。每個(gè)中間件都接受上一個(gè)中間件的執(zhí)行結(jié)果作為輸入值
3.每個(gè)中間件都可以停止數(shù)據(jù)的進(jìn)一步處理,只需要簡(jiǎn)單地不調(diào)用它的回調(diào)函數(shù)或者將錯(cuò)誤傳遞給回調(diào)函數(shù)。當(dāng)發(fā)生錯(cuò)誤時(shí),通常會(huì)觸發(fā)執(zhí)行另一個(gè)專門處理錯(cuò)誤的中間件
項(xiàng)目實(shí)戰(zhàn)
通用中間件開發(fā)
通用中間件使用 ajax
如上我們?cè)诎l(fā)送請(qǐng)求之前加入了類型轉(zhuǎn)換、數(shù)據(jù)校驗(yàn),將數(shù)據(jù)的業(yè)務(wù)處理使用中間件模式剝離,使得處理過程模塊化,維護(hù)性提升。
中間件升級(jí)-事件回調(diào)
每個(gè)中間件的過程都是不可控制的,全部都交由中間類去統(tǒng)一調(diào)用,我們可以加入事件回調(diào),方便我們?cè)谥虚g件處理過程中擁有額外的邏輯能力
將上述的使用方法再改造一下,方便實(shí)際業(yè)務(wù)中使用
上述的項(xiàng)目實(shí)例是采用 ajax 來演示,實(shí)際通用的中間件類,可以在業(yè)務(wù)中將一些 **流程化執(zhí)行的任務(wù) **拆分出來,例如表單驗(yàn)證、多重條件判斷等等
多種條件判斷
將流程化執(zhí)行的多種條件判斷通過中間件解耦,可以使得條件判斷方法更加清晰。一般當(dāng)你需要使用中介者來改造業(yè)務(wù)邏輯的時(shí)候,前端的項(xiàng)目確實(shí)有點(diǎn)復(fù)雜了。
現(xiàn)在STAR現(xiàn)在是在騰訊課堂里面分享自己的經(jīng)驗(yàn),感謝興趣的朋友可以加Q群:1146649671
中獲取STAR在騰訊課堂分享的鏈接,還可以獲取學(xué)習(xí)資料 面試文檔等
在javascript中并沒有原生的創(chuàng)建或者實(shí)現(xiàn)接口的方式,或者判定一個(gè)類型是否實(shí)現(xiàn)了某個(gè)接口,我們只能利用js的靈活性的特點(diǎn),模擬接口。
在javascript中實(shí)現(xiàn)接口有三種方式:注釋描述、屬性驗(yàn)證、鴨子模型。
note:因?yàn)槲铱吹氖怯⑽臅g水平有限,不知道有些詞匯如何翻譯,大家只能領(lǐng)會(huì)精神了。
1. 注釋描述 (Describing Interfaces with Comments)
例子:
復(fù)制代碼 代碼如下:
/*
interface Composite {
function add(child);
function remove(child);
function getChild(index);
}
interface FormItem {
function save();
}
*/
var CompositeForm = function(id, method, action) { // implements Composite, FormItem
...
};
//Implement the Composite interface.
CompositeForm.prototype.add = function(child) {
...
};
CompositeForm.prototype.remove = function(child) {
...
};
CompositeForm.prototype.getChild = function(index) {
...
};
// Implement the FormItem interface.
CompositeForm.prototype.save = function() {
...
};
模擬其他面向?qū)ο笳Z言,使用interface 和 implements關(guān)鍵字,但是需要將他們注釋起來,這樣就不會(huì)有語法錯(cuò)誤。
這樣做的目的,只是為了告訴其他編程人員,這些類需要實(shí)現(xiàn)什么方法,需要在編程的時(shí)候加以注意。但是沒有提供一種驗(yàn)證方式,這些類是否正確實(shí)現(xiàn)了這些接口中的方法,這種方式就是一種文檔化的作法。
2. 屬性驗(yàn)證(Emulating Interfaces with Attribute Checking)
例子:
復(fù)制代碼 代碼如下:
/* interface
Composite {
function add(child);
function remove(child);
function getChild(index);
}
interface FormItem {
function save();
}
*/
var CompositeForm = function(id, method, action) {
this.implementsInterfaces = ['Composite', 'FormItem'];
...
};
...
function addForm(formInstance) {
if(!implements(formInstance, 'Composite', 'FormItem')) {
throw new Error("Object does not implement a required interface.");
}
...
}
// The implements function, which checks to see if an object declares that it
// implements the required interfaces.
function implements(object) {
for(var i = 1; i arguments.length; i++) {
// Looping through all arguments
// after the first one.
var interfaceName = arguments[i];
var interfaceFound = false;
for(var j = 0; j object.implementsInterfaces.length; j++) {
if(object.implementsInterfaces[j] == interfaceName) {
interfaceFound = true;
break;
}
}
if(!interfaceFound) {
return false;
// An interface was not found.
}
}
return true;
// All interfaces were found.
}
這種方式比第一種方式有所改進(jìn),接口的定義仍然以注釋的方式實(shí)現(xiàn),但是添加了驗(yàn)證方法,判斷一個(gè)類型是否實(shí)現(xiàn)了某個(gè)接口。
3.鴨子類型(Emulating Interfaces with Duck Typing)
復(fù)制代碼 代碼如下:
// Interfaces.
var Composite = new Interface('Composite', ['add', 'remove', 'getChild']);
var FormItem = new Interface('FormItem', ['save']);
// CompositeForm class
var CompositeForm = function(id, method, action) {
...
};
...
function addForm(formInstance) {
ensureImplements(formInstance, Composite, FormItem);
// This function will throw an error if a required method is not implemented.
...
}
// Constructor.
var Interface = function(name, methods) {
if(arguments.length != 2) {
throw new Error("Interface constructor called with "
+ arguments.length + "arguments, but expected exactly 2.");
}
this.name = name;
this.methods = [];
for(var i = 0, len = methods.length; i len; i++) {
if(typeof methods[i] !== 'string') {
throw new Error("Interface constructor expects method names to be "
+ "passed in as a string.");
}
this.methods.push(methods[i]);
}
};
// Static class method.
Interface.ensureImplements = function(object) {
if(arguments.length 2) {
throw new Error("Function Interface.ensureImplements called with "
+arguments.length + "arguments, but expected at least 2.");
}
for(var i = 1, len = arguments.length; i len; i++) {
var interface = arguments[i];
if(interface.constructor !== Interface) {
throw new Error("Function Interface.ensureImplements expects arguments"
+ "two and above to be instances of Interface.");
}
for(var j = 0, methodsLen = interface.methods.length; j methodsLen; j++) {
var method = interface.methods[j];
if(!object[method] || typeof object[method] !== 'function') {
throw new Error("Function Interface.ensureImplements: object "
+ "does not implement the " + interface.name + " interface. Method " + method + " was not found.");
}
}
}
};
何時(shí)使用接口?
一直使用嚴(yán)格的類型驗(yàn)證并不適合,因?yàn)榇蠖鄶?shù)javascript程序員已經(jīng)在沒有接口和接口驗(yàn)證的情況下編程多年。當(dāng)你用設(shè)計(jì)模式開始設(shè)計(jì)一個(gè)很復(fù)雜的系統(tǒng)的時(shí)候,使用接口更有益處。看起來使用接口好像限制了javascript的靈活性,但實(shí)際上他讓你的代碼變得更加的松耦合。他使你的代碼變得更加靈活,你可以傳送任何類型的變量,并且保證他有你想要的方法。有很多場(chǎng)景接口非常適合使用。
在一個(gè)大型系統(tǒng)里,很多程序員一起參與開發(fā)項(xiàng)目,接口就變得非常必要了。程序員經(jīng)常要訪問一個(gè)還沒有實(shí)現(xiàn)的api,或者為其他程序員提供別人依賴的一個(gè)方法存根,在這種情況下,接口變得相當(dāng)?shù)挠袃r(jià)值。他們可以文檔化api,并作為編程的契約。當(dāng)存根被實(shí)現(xiàn)的api替換的時(shí)候你能立即知道,如果在開發(fā)過程中api有所變動(dòng),他能被另一個(gè)實(shí)現(xiàn)該接口的方法無縫替換。
如何使用接口?
首先要解決的問題是,在你的代碼中是否適合使用接口。如果是小項(xiàng)目,使用接口會(huì)增加代碼的復(fù)雜度。所以你要確定使用接口的情況下,是否是益處大于弊端。如果要使用接口,下面有幾條建議:
1.引用Interface 類到你的頁面文件。interface的源文件你可以再如下站點(diǎn)找到: .
2.檢查你的代碼,確定哪些方法需要抽象到接口里面。
3.創(chuàng)建接口對(duì)象,沒個(gè)接口對(duì)象里面包含一組相關(guān)的方法。
4.移除所有構(gòu)造器驗(yàn)證,我們將使用第三種接口實(shí)現(xiàn)方式,也就是鴨子類型。
5.用Interface.ensureImplements替代構(gòu)造器驗(yàn)證。
您可能感興趣的文章:
小議javascript 設(shè)計(jì)模式 推薦
JavaScript 設(shè)計(jì)模式之組合模式解析
javascript 設(shè)計(jì)模式之單體模式 面向?qū)ο髮W(xué)習(xí)基礎(chǔ)
JavaScript 設(shè)計(jì)模式 安全沙箱模式
JavaScript設(shè)計(jì)模式之觀察者模式(發(fā)布者-訂閱者模式)
JavaScript設(shè)計(jì)模式之原型模式(Object.create與prototype)介紹
JavaScript設(shè)計(jì)模式之工廠方法模式介紹
javascript設(shè)計(jì)模式之中介者模式Mediator
學(xué)習(xí)JavaScript設(shè)計(jì)模式之責(zé)任鏈模式
當(dāng)前名稱:javascript解耦,解耦的定義
本文來源:http://chinadenli.net/article32/dsgsjsc.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供定制網(wǎng)站、App設(shè)計(jì)、小程序開發(fā)、網(wǎng)站維護(hù)、網(wǎng)頁設(shè)計(jì)公司、建站公司
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)