JavaScript 依賴注入實(shí)現(xiàn)
隨著AngularJS的流行,依賴注入開始在JavaScript領(lǐng)域獲得不少的關(guān)注。 DI最突出的好處在于開發(fā)可復(fù)用可測試的代碼單元。 本文以簡易的代碼解釋DI的實(shí)現(xiàn)機(jī)制,更多對DI優(yōu)缺點(diǎn)的討論可參考: 什么時(shí)候應(yīng)該使用依賴注入 一文。
一個基本的DI用例每個模塊聲明自己的依賴,并提供自己的服務(wù)。例如:
di.service(’foo’, [’bar’], function foo(bar){ function Foo(){ this.bar = bar; } this.prototype.greeting = function(){ console.log(’hello, world’); } return Foo;}); var foo = di.container.get(’foo’);foo.greeting();
注意依賴注入和CommonJS(或AMD)的區(qū)別, foo 只需要聲明其依賴項(xiàng) bar 而不需要主動獲取。 正是這一點(diǎn)使得 function foo 對依賴所處的位置和構(gòu)建方法都完全無知, function foo 成為可測試、可復(fù)用的代碼單元。
DI框架的設(shè)計(jì)注冊服務(wù)和使用服務(wù)應(yīng)該在不同時(shí)期進(jìn)行。 作為一種特殊的依賴解決工具,DI框架將軟件單元的生命周期分為注冊階段和運(yùn)行階段。 上述例子中,在注冊階段提供 foo 和 bar 服務(wù),在運(yùn)行階段獲取并使用這些服務(wù)。 多數(shù)DI框架都采取lazy construction的策略,該策略也避免了在注冊階段進(jìn)行構(gòu)造的困難。
服務(wù)的定制可以在注冊階段后運(yùn)行階段前進(jìn)行。 AngularJS 1 引入配置階段來定制這些服務(wù),其Provider可以理解為一個特化的工廠對象。 BottleJS 則使用修飾器和中間件來支持對服務(wù)的定制。
使用IoC容器來索引服務(wù)實(shí)例或存儲服務(wù)提供者。 當(dāng)有人提供服務(wù)時(shí)就把它加入到容器中, 當(dāng)有人使用服務(wù)時(shí)就從容器中查找提供者并生成一個服務(wù)實(shí)例。 通常服務(wù)的實(shí)例可以被緩存。
DI框架的實(shí)現(xiàn)先來實(shí)現(xiàn)最常見的接口函數(shù) .service() ,該接口用來注冊一個服務(wù)的構(gòu)造器。 被傳入的函數(shù)將會被進(jìn)行 new 操作。
var di = { container: {}};di.service = function(name, Constructor) { defineLazyProperty(name, () => new Constructor());}; function defineLazyProperty(name, getter){ Object.defineProperty(di.container, name, {configurable: true,get: function() { var obj = getter(container); Object.defineProperty(di.container, name, {configurable: false value: obj }); return obj;} });}
Object.defineProperty 在這里用來做服務(wù)緩存。 只在第一次構(gòu)建服務(wù)時(shí)調(diào)用構(gòu)造器,后續(xù)的訪問就是直接讀取IoC容器的屬性。 它是ES5的標(biāo)準(zhǔn)方法 兼容性非常好 。 有了 defineLazyProperty() 方法,這些常用的注冊接口實(shí)現(xiàn)就很直觀了:
di.factory = function(name, factory) { return defineLazyProperty(name, factory);};di.provider = function(name, Provider) { return defineLazyProperty(name, function(){ var provider = new Provider(); return provider.$get(); });};di.value = function(name, val) { return defineLazyProperty(name, () => val);};
服務(wù)的定制接口就不再贅述了,值得一提的是統(tǒng)一的服務(wù)定制需要統(tǒng)一的服務(wù)構(gòu)造方法, 而不是直接調(diào)用 .defineLazyProperty() 生成屬性。 AngularJS 中這些策略都由Provider來實(shí)現(xiàn), 其他的所有服務(wù)注冊方法都借由Provider來實(shí)現(xiàn)。
來自:http://harttle.com/2016/11/19/javascript-dependency-injection-implementation.html
相關(guān)文章:
1. 使用Python webdriver圖書館搶座自動預(yù)約的正確方法2. Linux刪除系統(tǒng)自帶版本Python過程詳解3. PHP如何開啟Opcache功能提升程序處理效率4. Python3 json模塊之編碼解碼方法講解5. 在線php代碼縮進(jìn)、代碼美化工具:PHP Formatter6. Android 簡單的實(shí)現(xiàn)滑塊拼圖驗(yàn)證碼功能7. Python 合并拼接字符串的方法8. ASP.NET MVC使用jQuery ui的progressbar實(shí)現(xiàn)進(jìn)度條9. Android Studio實(shí)現(xiàn)格式化XML代碼順序10. 淺談由position屬性引申的css進(jìn)階討論

網(wǎng)公網(wǎng)安備