摘要:我們開始使用的時候,它的雙向數據綁定是最讓我們印象深刻的,那第二個就應該算是它的那神奇的依賴注入的功能了。來實現依賴注入現在大部分的框架都提供依賴注入機制的模塊,可能會叫做。
舉個栗子我們開始使用AngularJS的時候,它的雙向數據綁定是最讓我們印象深刻的,那第二個就應該算是它的那神奇的依賴注入的功能了。
function myController = ($scope, $http){ $http.get("users/users.json").success(function(data){ $scope.users = data; }) }
這是一個典型的angularjs的控制器,他發送了一個http請求,從后臺獲取json數據,然后把他傳遞給當前作用域。你會發現,我們并沒有執行這個myController函數(我們沒有機會給它傳遞參數),其實,是angular這個框架幫我們做了;那么,$scope, $http這些變量從哪里來的呢? 這是angular的一個非常酷的特性,我們一步步來實現一個簡單的注入器,從而知道它是怎么實現的。
傳統的方式現在,我們有一個js函數去把用戶列表展示在網頁上,那么這個函數就需要從ajax獲取過來的數據和用于展示數據的DOM元素。為了簡單點,我們直接用靜態數據了來代替ajax的http請求:
var data = ["John", "Steve", "David"]; var body = document.querySelector("body"); var ajaxFn = { get: function(path, cb) { console.log(path + " requested"); cb(data); } }
我們把body標簽作為列表的容器,ajaxFn是模擬ajax請求的對象,data是一個包含所有用戶的數組。下面來使用:
var displayUsers = function(domEl, ajax) { ajax.get("/api/users", function(users) { var html = ""; for(var i=0; i < users.length; i++) { html += "" + users[i] + "
"; } domEl.innerHTML = html; }); }
很明顯,我們運行displayUsers(body, ajaxFn),我們將會看到三個用戶名顯示在網頁上,同時控制臺輸出了/api/users requested。那這樣的話,我們可以認為我們的displayUsers函數有兩個依賴,body和ajaxFn.
那么現在,我們的目的是使displayUsers這個函數在不傳參數的情況下照樣工作,即,運行displayUsers()要得到和上面一樣的結果,如果我們直接運行,你會發現報錯了:
Uncaught TypeError: Cannot read property "get" of undefined
很明顯是因為ajax這個參數沒有定義。
來實現依賴注入現在大部分的框架都提供依賴注入機制的模塊,可能會叫做:injector。為了在某個地方使用一個依賴,我們需要在那個地方注冊那個依賴:
來創建我們的injector:
var injector = { storage: {}, register: function(name, resource) { this.storage[name] = resource; }, resolve: function(target) { } };
我們只需要兩個方法,第一個是register, 接收我們的依賴并將它存儲起來。第二個方法是resolve,這個方法接收的參數是我們我們要注入依賴的對象,這里的關鍵的點就是這個注入器不應該調用我們的函數,所以我們在resolve方法中返回一個閉包來包裹我們的target,然后再調用它:
resolve: function(target) { return function() { target(); }; }
那么到現在呢,我們的注入器依然是不可用的:
displayUsers = injector.resolve(displayUsers); displayUsers();
我們依然得到同樣的錯誤,你覺得少了什么呢?絕壁就是依賴項了,所以我們下一步就是要找出這個函數的依賴項,如何找? 這是比較棘手的問題,不過我們可以參考angularjs的方式:
var FN_ARGS = /^functions*[^(]*(s*([^)]*))/m; var STRIP_COMMENTS = /((//.*$)|(/*[sS]*?*/))/mg; ... function annotate(fn) { ... fnText = fn.toString().replace(STRIP_COMMENTS, ""); argDecl = fnText.match(FN_ARGS); ... } We purpo
這里省略了一些細節部分,我們需要注意的就是annotate這個函數,它負責將目標函數轉換為一個字符串,刪除它的注釋(如果有),然后提取他的參數(依賴項):
resolve: function(target) { var FN_ARGS = /^functions*[^(]*(s*([^)]*))/m; var STRIP_COMMENTS = /((//.*$)|(/*[sS]*?*/))/mg; fnText = target.toString().replace(STRIP_COMMENTS, ""); argDecl = fnText.match(FN_ARGS); console.log(argDecl); return function() { target(); } }
上面主要是通過正則表達式來找到依賴項,來看看結果:
你會看到返回的數組中包含了我們需要的依賴項,我們找到它們并用注入器注冊和存儲:
resolve: function(target) { var FN_ARGS = /^functions*[^(]*(s*([^)]*))/m; var STRIP_COMMENTS = /((//.*$)|(/*[sS]*?*/))/mg; fnText = target.toString().replace(STRIP_COMMENTS, ""); argDecl = fnText.match(FN_ARGS)[1].split(/, ?/g); var args = []; for(var i=0; i現在,我們可以使用我們的注入器了:
injector.register("domEl", body); injector.register("ajax", ajaxFn); displayUsers = injector.resolve(displayUsers); displayUsers();你會發現得到了和剛開始一樣的結果。
這樣做有什么優點呢?有點就是我們可以把DOM元素和ajaxFn注入到任何一個函數中,我們甚至可以將我們的應用程序配置成這樣的方式,那我們就不用通過繼承來傳遞這些對象了。這僅僅是injector的register和resolve方法而已,我們的注入器還不夠完美,還有擴展空間,比如定義作用域scope.
而angularjs中的依賴注入更加強大:
displayUsers = injector.resolve(["domEl", "ajax", displayUsers]);和displayUsers 不同,它傳遞的是真實的依賴名稱。
譯自:http://www.sitepoint.com/revealing-magic-javascript/
有錯誤還請指正!
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/85840.html
摘要:入門一前言目前來說相對于現在流行的高版本以及來說實屬是老套的前端框架了,當然這都不重要,沒有完美的框架,只有不斷優化的代碼。通過使用我們稱為指令的結構,讓瀏覽器能夠識別新的語法。使用作為輸入,而不是字符串,是區別于其它的框架的最大原因。 AngularJs 入門(一) 前言 AngularJs目前來說相對于現在流行的高版本ng2、ng4,以及Vue2.0、React來說實屬是老套的前...
摘要:上一篇譯精通使用開發四下一篇譯精通使用開發六書名合作對象正如所見,提供了一種將對象組織為模塊的方式。模塊不僅可以注冊可以直接被框架所調用的對象控制器,過濾器等,還可以使用任何應用開發者所定義的對象。 上一篇:【譯】《精通使用AngularJS開發Web App》(四) 下一篇:【譯】《精通使用AngularJS開發Web App》(六) 書名:Mastering Web Applic...
摘要:代碼代碼需要注意的地方這個方法只適合未經過壓縮和混淆的代碼因為需要原始未經壓縮的參數列表來進行解析。代碼代碼注意的地方行內聲明的方式允許我們直接傳入一個參數數組而不是一個函數。 AngularJS 依賴注入的方法 1. 通過函數的參數進行推斷式注入聲明 如果沒有明確的什么, AngularJS 會假定參數名稱就是依賴的名稱。因此, 它會在內部調用函數對象的 toString() 方法...
閱讀 4722·2021-11-15 11:39
閱讀 2691·2021-11-11 16:55
閱讀 2200·2021-10-25 09:44
閱讀 3504·2021-09-22 16:02
閱讀 2433·2019-08-30 15:55
閱讀 3122·2019-08-30 13:46
閱讀 2656·2019-08-30 13:15
閱讀 1944·2019-08-30 11:12