中文字幕免费精品_亚洲视频自拍_亚洲综合国产激情另类一区_色综合咪咪久久

JavaScript中的依賴注入詳解
來源:易賢網(wǎng) 閱讀:2987 次 日期:2015-03-19 14:53:03
溫馨提示:易賢網(wǎng)小編為您整理了“JavaScript中的依賴注入詳解”,方便廣大網(wǎng)友查閱!

這篇文章主要介紹了JavaScript中的依賴注入詳解,本文講解了requirejs/AMD方法、反射(reflection)方法等內(nèi)容,需要的朋友可以參考下

計(jì)算機(jī)編程的世界其實(shí)就是一個(gè)將簡(jiǎn)單的部分不斷抽象,并將這些抽象組織起來的過程。JavaScript也不例外,在我們使用JavaScript編寫應(yīng)用時(shí),我們是不是都會(huì)使用到別人編寫的代碼,例如一些著名的開源庫或者框架。隨著我們項(xiàng)目的增長(zhǎng),我們需要依賴的模塊變得越來越多,這個(gè)時(shí)候,如何有效的組織這些模塊就成了一個(gè)非常重要的問題。依賴注入解決的正是如何有效組織代碼依賴模塊的問題。你可能在一些框架或者庫種聽說過“依賴注入”這個(gè)詞,比如說著名的前端框架AngularJS,依賴注入就是其中一個(gè)非常重要的特性。但是,依賴注入根本就不是什么新鮮玩意,它在其他的編程語言例如PHP中已經(jīng)存在已久。同時(shí),依賴注入也沒有想象種那樣復(fù)雜。在本文中,我們將一起來學(xué)習(xí)JavaScript中的依賴注入的概念,深入淺出的講解如何編寫“依賴注入風(fēng)格”的代碼。

名單

JavaScript中的依賴注入詳解 三聯(lián)

目標(biāo)設(shè)定

假設(shè)我們現(xiàn)在擁有兩個(gè)模塊。第一個(gè)模塊的作用是發(fā)送Ajax請(qǐng)求,而第二個(gè)模塊的作用則是用作路由。

代碼如下:

var service = function() {

return { name: 'Service' };

}

var router = function() {

return { name: 'Router' };

}

這時(shí),我們編寫了一個(gè)函數(shù),它需要使用上面提到的兩個(gè)模塊:

代碼如下:

var doSomething = function(other) {

var s = service();

var r = router();

};

在這里,為了讓我們的代碼變得有趣一些,這個(gè)參數(shù)需要多接收幾個(gè)參數(shù)。當(dāng)然,我們完全可以使用上面的代碼,但是無論從哪個(gè)方面來看上面的代碼都略顯得不那么靈活。要是我們需要使用的模塊名稱變?yōu)镾erviceXML或者ServiceJSON該怎么辦?或者說如果我們基于測(cè)試的目的想要去使用一些假的模塊改怎么辦。這時(shí),我們不能僅僅去編輯函數(shù)本身。因此我們需要做的第一件事情就是將依賴的模塊作為參數(shù)傳遞給函數(shù),代碼如下所示:

代碼如下:

var doSomething = function(service, router, other) {

var s = service();

var r = router();

};

在上面的代碼中,我們完全傳遞了我們所需要的模塊。但是這又帶來了一個(gè)新的問題。假設(shè)我們?cè)诖a的哥哥部分都調(diào)用了doSomething方法。這時(shí),如果我們需要第三個(gè)依賴項(xiàng)該怎么辦。這個(gè)時(shí)候,去編輯所有的函數(shù)調(diào)用代碼并不是一個(gè)明智的方法。因此,我們需要一段代碼來幫助我們做這件事情。這就是依賴注入器試圖去解決的問題。現(xiàn)在我們可以來定下我們的目標(biāo)了:

1.我們應(yīng)該能夠去注冊(cè)依賴項(xiàng)

2.依賴注入器應(yīng)該接收一個(gè)函數(shù),然后返回一個(gè)能夠獲取所需資源的函數(shù)

3.代碼不應(yīng)該復(fù)雜,而應(yīng)該簡(jiǎn)單友好

4.依賴注入器應(yīng)該保持傳遞的函數(shù)作用域

5.傳遞的函數(shù)應(yīng)該能夠接收自定義的參數(shù),而不僅僅是被描述的依賴項(xiàng)

requirejs/AMD方法

或許你已經(jīng)聽說過了大名鼎鼎的requirejs,它是一個(gè)能夠很好的解決依賴注入問題的庫:

代碼如下:

define(['service', 'router'], function(service, router) {

// ...

});

requirejs的思想是首先我們應(yīng)該去描述所需要的模塊,然后編寫你自己的函數(shù)。其中,參數(shù)的順序很重要。假設(shè)我們需要編寫一個(gè)叫做injector的模塊,它能夠?qū)崿F(xiàn)類似的語法。

代碼如下:

var doSomething = injector.resolve(['service', 'router'], function(service, router, other) {

expect(service().name).to.be('Service');

expect(router().name).to.be('Router');

expect(other).to.be('Other');

});

doSomething("Other");

在繼續(xù)往下之前,需要說明的一點(diǎn)是在doSomething的函數(shù)體中我們使用了expect.js這個(gè)斷言庫來確保代碼的正確性。這里有一點(diǎn)類似TDD(測(cè)試驅(qū)動(dòng)開發(fā))的思想。

現(xiàn)在我們正式開始編寫我們的injector模塊。首先它應(yīng)該是一個(gè)單體,以便它能夠在我們應(yīng)用的各個(gè)部分都擁有同樣的功能。

代碼如下:

var injector = {

dependencies: {},

register: function(key, value) {

this.dependencies[key] = value;

},

resolve: function(deps, func, scope) {

}

}

這個(gè)對(duì)象非常的簡(jiǎn)單,其中只包含兩個(gè)函數(shù)以及一個(gè)用于存儲(chǔ)目的的變量。我們需要做的事情是檢查deps數(shù)組,然后在dependencies變量種尋找答案。剩余的部分,則是使用.apply方法去調(diào)用我們傳遞的func變量:

代碼如下:

resolve: function(deps, func, scope) {

var args = [];

for(var i=0; i<deps.length, d=deps[i]; i++) {

if(this.dependencies[d]) {

args.push(this.dependencies[d]);

} else {

throw new Error('Can\'t resolve ' + d);

}

}

return function() {

func.apply(scope || {}, args.concat(Array.prototype.slice.call(arguments, 0)));

}

}

如果你需要指定一個(gè)作用域,上面的代碼也能夠正常的運(yùn)行。

在上面的代碼中,Array.prototype.slice.call(arguments, 0)的作用是將arguments變量轉(zhuǎn)換為一個(gè)真正的數(shù)組。到目前為止,我們的代碼可以完美的通過測(cè)試。但是這里的問題是我們必須要將需要的模塊寫兩次,而且不能夠隨意排列順序。額外的參數(shù)總是排在所有的依賴項(xiàng)之后。

反射(reflection)方法

根據(jù)維基百科中的解釋,反射(reflection)指的是程序可以在運(yùn)行過程中,一個(gè)對(duì)象可以修改自己的結(jié)構(gòu)和行為。在JavaScript中,簡(jiǎn)單來說就是閱讀一個(gè)對(duì)象的源碼并且分析源碼的能力。還是回到我們的doSomething方法,如果你調(diào)用doSomething.toString()方法,你可以獲得下面的字符串:

代碼如下:

"function (service, router, other) {

var s = service();

var r = router();

}"

這樣一來,只要使用這個(gè)方法,我們就可以輕松的獲取到我們想要的參數(shù),以及更重要的一點(diǎn)就是他們的名字。這也是AngularJS實(shí)現(xiàn)依賴注入所使用的方法。在AngularJS的代碼中,我們可以看到下面的正則表達(dá)式:

代碼如下:

/^function\s*[^\(]*\(\s*([^\)]*)\)/m

我們可以將resolve方法修改成如下所示的代碼:

代碼如下:

resolve: function() {

var func, deps, scope, args = [], self = this;

func = arguments[0];

deps = func.toString().match(/^function\s*[^\(]*\(\s*([^\)]*)\)/m)[1].replace(/ /g, '').split(',');

scope = arguments[1] || {};

return function() {

var a = Array.prototype.slice.call(arguments, 0);

for(var i=0; i<deps.length; i++) {

var d = deps[i];

args.push(self.dependencies[d] && d != '' ? self.dependencies[d] : a.shift());

}

func.apply(scope || {}, args);

}

}

我們使用上面的正則表達(dá)式去匹配我們定義的函數(shù),我們可以獲取到下面的結(jié)果:

代碼如下:

["function (service, router, other)", "service, router, other"]

此時(shí),我們只需要第二項(xiàng)。但是一旦我們?nèi)コ硕嘤嗟目崭癫⒁?來切分字符串以后,我們就得到了deps數(shù)組。下面的代碼就是我們進(jìn)行修改的部分:

代碼如下:

var a = Array.prototype.slice.call(arguments, 0);

...

args.push(self.dependencies[d] && d != '' ? self.dependencies[d] : a.shift());

在上面的代碼中,我們遍歷了依賴項(xiàng)目,如果其中有缺失的項(xiàng)目,如果依賴項(xiàng)目中有缺失的部分,我們就從arguments對(duì)象中獲取。如果一個(gè)數(shù)組是空數(shù)組,那么使用shift方法將只會(huì)返回undefined,而不會(huì)拋出一個(gè)錯(cuò)誤。到目前為止,新版本的injector看起來如下所示:

代碼如下:

var doSomething = injector.resolve(function(service, other, router) {

expect(service().name).to.be('Service');

expect(router().name).to.be('Router');

expect(other).to.be('Other');

});

doSomething("Other");

在上面的代碼中,我們可以隨意混淆依賴項(xiàng)的順序。

但是,沒有什么是完美的。反射方法的依賴注入存在一個(gè)非常嚴(yán)重的問題。當(dāng)代碼簡(jiǎn)化時(shí),會(huì)發(fā)生錯(cuò)誤。這是因?yàn)樵诖a簡(jiǎn)化的過程中,參數(shù)的名稱發(fā)生了變化,這將導(dǎo)致依賴項(xiàng)無法解析。例如:

代碼如下:

var doSomething=function(e,t,n){var r=e();var i=t()}

因此我們需要下面的解決方案,就像AngularJS中那樣:

代碼如下:

var doSomething = injector.resolve(['service', 'router', function(service, router) {

}]);

這和最一開始看到的AMD的解決方案很類似,于是我們可以將上面兩種方法整合起來,最終代碼如下所示:

代碼如下:

var injector = {

dependencies: {},

register: function(key, value) {

this.dependencies[key] = value;

},

resolve: function() {

var func, deps, scope, args = [], self = this;

if(typeof arguments[0] === 'string') {

func = arguments[1];

deps = arguments[0].replace(/ /g, '').split(',');

scope = arguments[2] || {};

} else {

func = arguments[0];

deps = func.toString().match(/^function\s*[^\(]*\(\s*([^\)]*)\)/m)[1].replace(/ /g, '').split(',');

scope = arguments[1] || {};

}

return function() {

var a = Array.prototype.slice.call(arguments, 0);

for(var i=0; i<deps.length; i++) {

var d = deps[i];

args.push(self.dependencies[d] && d != '' ? self.dependencies[d] : a.shift());

}

func.apply(scope || {}, args);

}

}

}

這一個(gè)版本的resolve方法可以接受兩個(gè)或者三個(gè)參數(shù)。下面是一段測(cè)試代碼:

代碼如下:

var doSomething = injector.resolve('router,,service', function(a, b, c) {

expect(a().name).to.be('Router');

expect(b).to.be('Other');

expect(c().name).to.be('Service');

});

doSomething("Other");

你可能注意到了兩個(gè)逗號(hào)之間什么都沒有,這并不是錯(cuò)誤。這個(gè)空缺是留給Other這個(gè)參數(shù)的。這就是我們控制參數(shù)順序的方法。

結(jié)語

在上面的內(nèi)容中,我們介紹了幾種JavaScript中依賴注入的方法,希望本文能夠幫助你開始使用依賴注入這個(gè)技巧,并且寫出依賴注入風(fēng)格的代碼。

更多信息請(qǐng)查看IT技術(shù)專欄

更多信息請(qǐng)查看腳本欄目
易賢網(wǎng)手機(jī)網(wǎng)站地址:JavaScript中的依賴注入詳解
由于各方面情況的不斷調(diào)整與變化,易賢網(wǎng)提供的所有考試信息和咨詢回復(fù)僅供參考,敬請(qǐng)考生以權(quán)威部門公布的正式信息和咨詢?yōu)闇?zhǔn)!

2026上岸·考公考編培訓(xùn)報(bào)班

  • 報(bào)班類型
  • 姓名
  • 手機(jī)號(hào)
  • 驗(yàn)證碼
關(guān)于我們 | 聯(lián)系我們 | 人才招聘 | 網(wǎng)站聲明 | 網(wǎng)站幫助 | 非正式的簡(jiǎn)要咨詢 | 簡(jiǎn)要咨詢須知 | 新媒體/短視頻平臺(tái) | 手機(jī)站點(diǎn) | 投訴建議
工業(yè)和信息化部備案號(hào):滇ICP備2023014141號(hào)-1 云南省教育廳備案號(hào):云教ICP備0901021 滇公網(wǎng)安備53010202001879號(hào) 人力資源服務(wù)許可證:(云)人服證字(2023)第0102001523號(hào)
云南網(wǎng)警備案專用圖標(biāo)
聯(lián)系電話:0871-65099533/13759567129 獲取招聘考試信息及咨詢關(guān)注公眾號(hào):hfpxwx
咨詢QQ:1093837350(9:00—18:00)版權(quán)所有:易賢網(wǎng)
云南網(wǎng)警報(bào)警專用圖標(biāo)
中文字幕免费精品_亚洲视频自拍_亚洲综合国产激情另类一区_色综合咪咪久久
国产精品爱久久久久久久| 欧美日韩中文字幕综合视频| 亚洲第一久久影院| 亚洲三级免费电影| 午夜精品福利一区二区蜜股av| 亚洲一区二区三区色| 久久精品人人做人人综合| 欧美精品不卡| 国产一区自拍视频| 亚洲无亚洲人成网站77777 | 久热国产精品| 国产精品高清网站| 在线观看欧美日本| 久久精品国产2020观看福利| 欧美午夜精品一区二区三区| 亚洲国产毛片完整版 | 国产精品一区二区久久久久| 亚洲人成在线观看一区二区| 久久精品中文字幕一区| 国产精品美女久久久久av超清| 亚洲乱码国产乱码精品精天堂 | 亚洲精品免费在线播放| 久久精品道一区二区三区| 欧美三区在线视频| 99国产精品私拍| 欧美va天堂va视频va在线| 一区二区在线看| 久久免费精品视频| 狠狠色狠狠色综合人人| 久久久777| 在线观看视频日韩| 两个人的视频www国产精品| 激情亚洲一区二区三区四区| 久久九九国产精品怡红院| 激情五月***国产精品| 麻豆国产精品777777在线| 亚洲第一网站免费视频| 欧美一区二区性| 国产一区二区三区在线观看免费| 欧美一区二区三区视频在线| 国产亚洲欧美色| 久久午夜视频| 在线国产欧美| 欧美+亚洲+精品+三区| 亚洲一区二三| 国产精品www色诱视频| 亚洲欧美另类在线观看| 国产日韩欧美麻豆| 久久精品国产亚洲一区二区| 国内视频精品| 男同欧美伦乱| 一本色道久久综合狠狠躁篇的优点| 欧美日韩中文字幕| 午夜视黄欧洲亚洲| 亚洲第一搞黄网站| 欧美日韩一级黄| 欧美中文日韩| 亚洲美女视频| 国产区亚洲区欧美区| 欧美不卡视频一区发布| 中文在线一区| 激情综合激情| 国产精品九九| 麻豆久久久9性大片| 亚洲一区二区三区精品在线观看| 国产香蕉97碰碰久久人人| 欧美激情第一页xxx| 欧美一级大片在线观看| 亚洲精品在线视频观看| 国外视频精品毛片| 欧美日韩在线观看一区二区| 久久久久久久性| 亚洲无线观看| 亚洲日本va午夜在线影院| 国产一区二区精品在线观看| 欧美日韩高清不卡| 久久亚洲春色中文字幕久久久| 亚洲视频久久| 亚洲精品自在久久| 久久高清免费观看| 国产精品高潮久久| 久久久久久久综合狠狠综合| 999在线观看精品免费不卡网站| 国产午夜精品久久久久久久| 欧美巨乳波霸| 欧美aaa级| 美女视频黄 久久| 久久精品一区四区| 亚洲欧美精品一区| 妖精视频成人观看www| 亚洲国产精品va| 伊人久久大香线| 国产精品亚洲综合色区韩国| 欧美日韩中文字幕在线视频| 毛片精品免费在线观看| 久久精品人人做人人综合| 亚洲欧美日韩一区| 亚洲欧美日韩在线观看a三区| 一本久道综合久久精品| 99re热精品| 99热精品在线| 亚洲少妇诱惑| 亚洲永久精品大片| 亚洲一区二区三区四区五区午夜 | 欧美二区在线观看| 久久综合九色欧美综合狠狠| 久久国产免费看| 久久久精品2019中文字幕神马| 午夜一区二区三视频在线观看| 亚洲一区二区欧美| 亚洲欧美日韩国产一区二区三区| 亚洲一区一卡| 欧美在线一二三| 久热爱精品视频线路一| 噜噜噜在线观看免费视频日韩| 你懂的网址国产 欧美| 欧美成黄导航| 欧美午夜片在线观看| 国产精品伦理| 国外精品视频| 99精品久久| 新片速递亚洲合集欧美合集| 久久精品国产精品亚洲综合| 老鸭窝毛片一区二区三区| 欧美不卡高清| 国产精品亚洲а∨天堂免在线| 国产一区二区三区久久 | 久久午夜av| 欧美日韩精品免费观看视频| 国产精品美女在线| 国内外成人在线| 亚洲美女免费视频| 亚洲自拍16p| 免费黄网站欧美| 欧美体内谢she精2性欧美| 国产日产欧美精品| 最新国产の精品合集bt伙计| 亚洲尤物在线| 欧美gay视频| 国产一区99| 亚洲一区二区黄| 免费久久99精品国产| 国产精品久久久一区麻豆最新章节 | 亚洲在线中文字幕| 久久在线免费| 国产欧美精品在线| 亚洲激情专区| 久久精品免费看| 欧美特黄一级大片| 91久久国产综合久久| 久久国产精品99国产精| 欧美日韩影院| 最新成人在线| 老牛影视一区二区三区| 国产精品永久免费视频| 99re这里只有精品6| 美女精品在线| 国语自产在线不卡| 亚洲欧美国产精品桃花| 欧美福利电影在线观看| 影音先锋亚洲视频| 久久黄色级2电影| 欧美日韩国产一区| 国内外成人免费激情在线视频| 一区二区三区欧美激情| 欧美精品久久久久久久久久| 曰韩精品一区二区| 久久久久久亚洲综合影院红桃| 国产精品夜夜夜| 午夜精品久久久| 国产精品国产三级国产普通话99| 日韩视频永久免费观看| 欧美高清视频在线播放| 91久久国产自产拍夜夜嗨| 快射av在线播放一区| 极品尤物av久久免费看| 久久免费黄色| 亚洲国产精品久久久久久女王| 久久这里有精品视频| 一区一区视频| 噜噜噜在线观看免费视频日韩| 樱桃视频在线观看一区| 狂野欧美激情性xxxx| 亚洲级视频在线观看免费1级| 欧美成人日本| 夜夜夜久久久| 国产精品试看| 久久久最新网址| 亚洲国产精品久久久久秋霞影院| 欧美国产日韩一区| 亚洲视频一区二区| 国产精品自拍小视频| 狂野欧美一区| 99国产精品久久| 国产精品一区在线观看你懂的| 久久久精品日韩| 亚洲每日在线| 国产欧美日韩在线| 免费视频久久| 一本久久a久久免费精品不卡|