1空盼、angularjs的幾大特性是什么?
雙向數(shù)據(jù)綁定新荤、依賴注入揽趾、模板、指令苛骨、MVC/MVVM
2篱瞎、列舉幾種常見的設(shè)計(jì)模式,寫出沒個代表的含義痒芝?
MVC :model view controller
MVVM :model view viewModel
3俐筋、請描述angularjs的運(yùn)行過程?
angularjs編譯所有的HTML元素標(biāo)簽严衬,然后在里面查找angular程序的入口 ng-app 每個元素上的指令是把所有指令收集起來根據(jù)優(yōu)先級依次編譯
4澄者、ng-bind和ng-model的區(qū)別是什么?
ng-bind只能展示數(shù)據(jù) ng-model可以操作數(shù)據(jù)
5请琳、請描述$scope的特點(diǎn)還有其最大的父類粱挡?
隨創(chuàng)建作用域創(chuàng)建的一個變量,就代表controller所代表的作用域俄精,其持有的對象和方法可在當(dāng)前及其子作用域生效
6询筏、原生js的延遲或回調(diào)在angularjs里能完美運(yùn)行嗎?怎么解決竖慧?可以用例子嫌套?
不能 需要用$apply來進(jìn)行傳播
7、{{ array | filter:{‘a(chǎn)ge’:23}:true }} 這個過濾里的true是什么意思圾旨?
是否用angular.equals進(jìn)行比較后為真才返回
8踱讨、自定義過濾創(chuàng)建后返回的是一個什么對象?
返回一個函數(shù)對象 并且函數(shù)內(nèi)要返回最后返回的對象
9碳胳、ng-repeat循環(huán)[1,3,2,4,3,4]數(shù)組會報錯嗎勇蝙?如果會怎么解決沫勿?
會因?yàn)橛兄貜?fù)的內(nèi)容 track by $index
10挨约、angular常用的服務(wù)中value和constant最大的區(qū)別是什么味混?
constant的創(chuàng)建要早于value 并且其可以在config配置中使用 value不行
11、常用服務(wù)中factory和service的最大區(qū)別是什么诫惭?
factory返回的對象當(dāng)我們使用它的時候手動初始化并返回翁锡,而service是當(dāng)我們第一次使用的時候angular幫我們初始化一次,然后以后使用的時候返回的都是這個對象夕土,factory創(chuàng)建的服務(wù)是代表的是其后面函數(shù)的返回值馆衔,這個返回值可以是任意類型,service不用返回怨绣,直接操作的就是自己
12角溃、怎么攔截服務(wù)?
在config配置里注入需要攔截的服務(wù)的名字+Provider來攔截
13篮撑、decorator的作用是什么减细?和攔截服務(wù)的區(qū)別是什么?
裝飾器不僅可以應(yīng)用在我們自己的服務(wù)上赢笨,也可以對angularjs核心服務(wù)進(jìn)行攔截未蝌、中斷甚至替換功能的操作,事實(shí)上angularjs的很多測試就是借助$provide.decorator()建立的茧妒、請寫一個配置路由的代碼段(只需要寫怎么聲明一個路由和其常用屬性的代碼段)
14萧吠、resolve的作用是什么?
如果設(shè)置了resolve屬性桐筏,angularjs會將列表中的元素都注入到控制器中纸型,列表對象可以是鍵(鍵值是會被注入到控制器中依賴的名字),也可以是工廠(即可以是一個服務(wù)的名字)
15梅忌、ngRoute默認(rèn)查找的路由是什么绊袋?$routeProvider.otherwise(’/index’)是什么作用?
是/ 設(shè)置路由的意外指向到/index
16铸鹰、$location.path(‘/home’)和$location.url(‘/home’)都可以進(jìn)行路由跳轉(zhuǎn)癌别,但是.path方法和.url方法最大的區(qū)別是什么?
.url方法:可以在跳轉(zhuǎn)的同時設(shè)置查詢串蹋笼,返回url的整個路徑展姐; 而.path方法:返回的路徑不包括?后面的部分剖毯;
17圾笨、什么是跨域,請簡要描述跨域的場景逊谋?
協(xié)議 域名 端口號有一個不一樣就是跨域擂达,也就是不同域名之間的訪問;
18胶滋、常使用的跨域方案就哪兩種板鬓?分別描述其利用的原理悲敷?
jsonp; post請求設(shè)置請求頭 ; jsonp利用的是script可以訪問外部信息的原理發(fā)送請求并且利用jsonp協(xié)議進(jìn)行數(shù)據(jù)交互 post設(shè)置請求頭跳過預(yù)請求來實(shí)現(xiàn)跨域
19俭令、請寫出$http網(wǎng)絡(luò)請求的幾種寫法后德,最少兩種
$http.(url).success(function(data){
}).error(function(error){
}) $http({ method:’’, url:url }).success(function(data){
}).error(function(error){
}) $http({ method:’*’, url:url }).then(function success(data){
},function error(error){
})
var promise = $http({ method:’get’, url:url }); promise.then(function(data){
},function(error){
}) 或者 promise.success(function(data){
}); promise.error(function(error){
});
20、ng-if 跟 ng-show/hide 的區(qū)別有哪些抄腔?
第一點(diǎn)區(qū)別是瓢湃,ng-if
在后面表達(dá)式為 true 的時候才創(chuàng)建這個 dom 節(jié)點(diǎn),ng-show
是初始時就創(chuàng)建了赫蛇,用 display:block
和 display:none
來控制顯示和不顯示绵患。
第二點(diǎn)區(qū)別是,ng-if
會(隱式地)產(chǎn)生新作用域悟耘,ng-switch
藏雏、 ng-include
等會動態(tài)創(chuàng)建一塊界面的也是如此。
這樣會導(dǎo)致作煌,在 ng-if
中用基本變量綁定 ng-model
掘殴,并在外層 div 中把此 model 綁定給另一個顯示區(qū)域,內(nèi)層改變時粟誓,外層不會同步改變奏寨,因?yàn)榇藭r已經(jīng)是兩個變量了。
{{name}}
#21鹰服、ng-show
不存在此問題病瞳,因?yàn)樗蛔詭б患壸饔糜颉?/p>
避免這類問題出現(xiàn)的辦法是,始終將頁面中的元素綁定到對象的屬性(data.x)而不是直接綁定到基本變量(x)上悲酷。
詳見 AngularJS 中的作用域
#22套菜、ng-repeat迭代數(shù)組的時候,如果數(shù)組中有相同值设易,會有什么問題逗柴,如何解決?
會提示 Duplicates in a repeater are not allowed.
加 track by $index
可解決顿肺。當(dāng)然戏溺,也可以 trace by 任何一個普通的值,只要能唯一性標(biāo)識數(shù)組中的每一項(xiàng)即可(建立 dom 和數(shù)據(jù)之間的關(guān)聯(lián))屠尊。
ng-click 中寫的表達(dá)式旷祸,能使用 JS 原生對象上的方法嗎?
不止是 ng-click 中的表達(dá)式讼昆,只要是在頁面中托享,都不能直接調(diào)用原生的 JS 方法,因?yàn)檫@些并不存在于與頁面對應(yīng)的 Controller 的 $scope 中。
舉個栗子:
{{parseInt(55.66)}}
會發(fā)現(xiàn)闰围,什么也沒有顯示赃绊。
但如果在 $scope 中添加了這個函數(shù):
$scope.parseInt = function(x){ return parseInt(x);}
這樣自然是沒什么問題了。
#23辫诅、對于這種需求凭戴,使用一個 filter 或許是不錯的選擇:
{{13.14 | parseIntFilter}}
app.filter('parseIntFilter', function(){ return function(item){ return parseInt(item); }})
{{now | 'yyyy-MM-dd'}}
這種表達(dá)式里面涧狮,豎線和后面的參數(shù)通過什么方式可以自定義炕矮?
filter,格式化數(shù)據(jù)者冤,接收一個輸入肤视,按某規(guī)則處理,返回處理結(jié)果涉枫。
內(nèi)置 filter
ng 內(nèi)置的 filter 有九種:
date(日期)
currency(貨幣)
limitTo(限制數(shù)組或字符串長度)
orderBy(排序)
lowercase(小寫)
uppercase(大寫)
number(格式化數(shù)字邢滑,加上千位分隔符,并接收參數(shù)限定小數(shù)點(diǎn)位數(shù))
filter(處理一個數(shù)組愿汰,過濾出含有某個子串的元素)
json(格式化 json 對象)
filter 有兩種使用方法困后,一種是直接在頁面里:
{{now | date : 'yyyy-MM-dd'}}
另一種是在 js 里面用:
// $filter('過濾器名稱')(需要過濾的對象, 參數(shù)1, 參數(shù)2,...)$filter('date')(now, 'yyyy-MM-dd hh:mm:ss');
24、自定義 filter
// 形式app.filter('過濾器名稱',function(){ return function(需要過濾的對象,過濾器參數(shù)1,過濾器參數(shù)2,...){ //...做一些事情 ?return 處理后的對象; }}); // 栗子app.filter('timesFilter', function(){ return function(item, times){ var result = ''; for(var i = 0; i < times; i++){ result += item; } return result; }})
25衬廷、factory摇予、service 和 provider 是什么關(guān)系?
factory
把 service 的方法和數(shù)據(jù)放在一個對象里吗跋,并返回這個對象
app.factory('FooService', function(){ return { target: 'factory', sayHello: function(){ return 'hello ' + this.target; } }});
service
通過構(gòu)造函數(shù)方式創(chuàng)建 service侧戴,返回一個實(shí)例化對象
app.service('FooService', function(){ var self = this; this.target = 'service'; this.sayHello = function(){ return 'hello ' + self.target; }});
provider
創(chuàng)建一個可通過 config 配置的 service,$get 中返回的跌宛,就是用 factory 創(chuàng)建 service 的內(nèi)容
app.provider('FooService', function(){ this.configData = 'init data'; this.setConfigData = function(data){ if(data){ this.configData = data; } } this.$get = function(){ var self = this; return { target: 'provider', sayHello: function(){ return self.configData + ' hello ' + this.target; } } }});// 此處注入的是 FooService 的 providerapp.config(function(FooServiceProvider){ FooServiceProvider.setConfigData('config data');});
從底層實(shí)現(xiàn)上來看酗宋,service 調(diào)用了 factory,返回其實(shí)例疆拘;factory 調(diào)用了 provider蜕猫,返回其 $get
中定義的內(nèi)容。factory 和 service 功能類似哎迄,只不過 factory 是普通 function丹锹,可以返回任何東西(return 的都可以被訪問,所以那些私有變量怎么寫芬失,你懂的)楣黍;service 是構(gòu)造器,可以不返回(綁定到 this 的都可以被訪問)棱烂;provider 是加強(qiáng)版 factory租漂,返回一個可配置的 factory。
詳見 AngularJS 之 Factory vs Service vs Provider
angular 的數(shù)據(jù)綁定采用什么機(jī)制?詳述原理
臟檢查機(jī)制哩治。
雙向數(shù)據(jù)綁定是 AngularJS 的核心機(jī)制之一秃踩。當(dāng) view 中有任何數(shù)據(jù)變化時,會更新到 model 业筏,當(dāng) model 中數(shù)據(jù)有變化時憔杨,view 也會同步更新,顯然蒜胖,這需要一個監(jiān)控消别。
原理就是,Angular 在 scope 模型上設(shè)置了一個 監(jiān)聽隊(duì)列台谢,用來監(jiān)聽數(shù)據(jù)變化并更新 view 寻狂。每次綁定一個東西到 view 上時 AngularJS 就會往 $watch
隊(duì)列里插入一條 $watch
,用來檢測它監(jiān)視的 model 里是否有變化的東西朋沮。當(dāng)瀏覽器接收到可以被 angular context 處理的事件時蛇券,$digest
循環(huán)就會觸發(fā),遍歷所有的 $watch
樊拓,最后更新 dom纠亚。
舉個栗子
increase 1
click 時會產(chǎn)生一次更新的操作(至少觸發(fā)兩次 $digest
循環(huán))
按下按鈕
瀏覽器接收到一個事件,進(jìn)入到 angular context
26筋夏、$digest
循環(huán)開始執(zhí)行蒂胞,查詢每個 $watch
是否變化
由于監(jiān)視 $scope
.val 的 $watch
報告了變化,因此強(qiáng)制再執(zhí)行一次 $digest
循環(huán)
新的 $digest
循環(huán)未檢測到變化
瀏覽器拿回控制器叁丧,更新 $scope
.val 新值對應(yīng)的 dom
$digest
循環(huán)的上限是 10 次(超過 10次后拋出一個異常啤誊,防止無限循環(huán))。
詳見 關(guān)于 AngularJS 的數(shù)據(jù)綁定
兩個平級界面塊 a 和 b拥娄,如果 a 中觸發(fā)一個事件蚊锹,有哪些方式能讓 b 知道?詳述原理
這個問題換一種說法就是稚瘾,如何在平級界面模塊間進(jìn)行通信牡昆。有兩種方法,一種是共用服務(wù)摊欠,一種是基于事件丢烘。
共用服務(wù)
在 Angular 中,通過 factory 可以生成一個單例對象些椒,在需要通信的模塊 a 和 b 中注入這個對象即可播瞳。
基于事件
這個又分兩種方式
第一種是借助父 controller。在子 controller 中向父 controller 觸發(fā)($emit
)一個事件免糕,然后在父 controller 中監(jiān)聽($on
)事件赢乓,再廣播($broadcast
)給子 controller 忧侧,這樣通過事件攜帶的參數(shù),實(shí)現(xiàn)了數(shù)據(jù)經(jīng)過父 controller牌芋,在同級 controller 之間傳播蚓炬。
第二種是借助 $rootScope
。每個 Angular 應(yīng)用默認(rèn)有一個根作用域 $rootScope
躺屁, 根作用域位于最頂層肯夏,從它往下掛著各級作用域。所以犀暑,如果子控制器直接使用 $rootScope
廣播和接收事件驯击,那么就可實(shí)現(xiàn)同級之間的通信。
詳見 AngularJS 中 Controller 之間的通信
一個 angular 應(yīng)用應(yīng)當(dāng)如何良好地分層母怜?
目錄結(jié)構(gòu)的劃分
對于小型項(xiàng)目余耽,可以按照文件類型組織缚柏,比如:
cssjs controllers models services filterstemplates
但是對于規(guī)模較大的項(xiàng)目苹熏,最好按業(yè)務(wù)模塊劃分,比如:
cssmodules account controllers models services filters templates disk controllers models services filters templates
modules 下最好再有一個 common 目錄來存放公共的東西币喧。
邏輯代碼的拆分
作為一個 MVVM 框架轨域,Angular 應(yīng)用本身就應(yīng)該按照 模型,視圖模型(控制器)杀餐,視圖來劃分干发。
這里邏輯代碼的拆分,主要是指盡量讓 controller 這一層很薄史翘。提取共用的邏輯到 service 中 (比如后臺數(shù)據(jù)的請求枉长,數(shù)據(jù)的共享和緩存,基于事件的模塊間通信等)琼讽,提取共用的界面操作到 directive 中(比如將日期選擇必峰、分頁等封裝成組件等),提取共用的格式化操作到 filter 中等等钻蹬。
在復(fù)雜的應(yīng)用中吼蚁,也可以為實(shí)體建立對應(yīng)的構(gòu)造函數(shù),比如硬盤(Disk)模塊问欠,可能有列表肝匆、新建、詳情這樣幾個視圖顺献,并分別對應(yīng)的有 controller旗国,那么可以建一個 Disk 構(gòu)造函數(shù),里面完成數(shù)據(jù)的增刪改查和驗(yàn)證操作注整,有跟 Disk 相關(guān)的 controller能曾,就注入 Disk 構(gòu)造器并生成一個實(shí)例嫁怀,這個實(shí)例就具備了增刪改查和驗(yàn)證方法。這樣既層次分明借浊,又實(shí)現(xiàn)了復(fù)用(讓 controller 層更薄了)塘淑。
參考 AngularJS在蘇寧云中心的深入實(shí)踐
27、angular 應(yīng)用常用哪些路由庫蚂斤,各自的區(qū)別是什么存捺?
Angular1.x 中常用 ngRoute 和 ui.router,還有一種為 Angular2 設(shè)計(jì)的 new router(面向組件)曙蒸。后面那個沒在實(shí)際項(xiàng)目中用過捌治,就不講了。
無論是 ngRoute 還是 ui.router纽窟,作為框架額外的附加功能肖油,都必須以 模塊依賴 的形式被引入。
區(qū)別
ngRoute 模塊是 Angular 自帶的路由模塊臂港,而 ui.router 模塊是基于 ngRoute模塊開發(fā)的第三方模塊森枪。
ui.router 是基于 state (狀態(tài))的, ngRoute 是基于 url 的审孽,ui.router模塊具有更強(qiáng)大的功能县袱,主要體現(xiàn)在視圖的嵌套方面。
使用 ui.router 能夠定義有明確父子關(guān)系的路由佑力,并通過 ui-view 指令將子路由模版插入到父路由模板的
中去式散,從而實(shí)現(xiàn)視圖嵌套。而在 ngRoute 中不能這樣定義打颤,如果同時在父子視圖中 使用了
會陷入死循環(huán)暴拄。
示例
ngRoute
var app = angular.module('ngRouteApp', ['ngRoute']);app.config(function($routeProvider){ $routeProvider .when('/main', { templateUrl: "main.html", controller: 'MainCtrl' }) .otherwise({ redirectTo: '/tabs' });
ui.router
var app = angular.module("uiRouteApp", ["ui.router"]);app.config(function($urlRouterProvider, $stateProvider){ $urlRouterProvider.otherwise("/index"); $stateProvider .state("Main", { url: "/main", templateUrl: "main.html", controller: 'MainCtrl' })
28、如果通過angular的directive規(guī)劃一套全組件化體系编饺,可能遇到哪些挑戰(zhàn)乖篷?
沒有自己用 directive 做過一全套組件,講不出反肋。
能想到的一點(diǎn)是那伐,組件如何與外界進(jìn)行數(shù)據(jù)的交互,以及如何通過簡單的配置就能使用吧石蔗。
分屬不同團(tuán)隊(duì)進(jìn)行開發(fā)的 angular 應(yīng)用罕邀,如果要做整合,可能會遇到哪些問題养距,如何解決诉探?
可能會遇到不同模塊之間的沖突。
比如一個團(tuán)隊(duì)所有的開發(fā)在 moduleA 下進(jìn)行棍厌,另一團(tuán)隊(duì)開發(fā)的代碼在 moduleB 下
angular.module('myApp.moduleA', []) .factory('serviceA', function(){ ... }) angular.module('myApp.moduleB', []) .factory('serviceA', function(){ ... }) angular.module('myApp', ['myApp.moduleA', 'myApp.moduleB'])
會導(dǎo)致兩個 module 下面的 serviceA 發(fā)生了覆蓋肾胯。
貌似在 Angular1.x 中并沒有很好的解決辦法竖席,所以最好在前期進(jìn)行統(tǒng)一規(guī)劃,做好約定敬肚,嚴(yán)格按照約定開發(fā)毕荐,每個開發(fā)人員只寫特定區(qū)塊代碼。
angular 的缺點(diǎn)有哪些艳馒?
強(qiáng)約束
導(dǎo)致學(xué)習(xí)成本較高憎亚,對前端不友好。
但遵守 AngularJS 的約定時弄慰,生產(chǎn)力會很高第美,對 Java 程序員友好。
不利于 SEO
因?yàn)樗袃?nèi)容都是動態(tài)獲取并渲染生成的陆爽,搜索引擎沒法爬取什往。
一種解決辦法是,對于正常用戶的訪問慌闭,服務(wù)器響應(yīng) AngularJS 應(yīng)用的內(nèi)容别威;對于搜索引擎的訪問,則響應(yīng)專門針對 SEO 的HTML頁面贡必。
性能問題
作為 MVVM 框架兔港,因?yàn)閷?shí)現(xiàn)了數(shù)據(jù)的雙向綁定庸毫,對于大數(shù)組仔拟、復(fù)雜對象會存在性能問題。
可以用來 優(yōu)化 Angular 應(yīng)用的性能 的辦法:
減少監(jiān)控項(xiàng)(比如對不會變化的數(shù)據(jù)采用單向綁定)
主動設(shè)置索引(指定 track by
飒赃,簡單類型默認(rèn)用自身當(dāng)索引利花,對象默認(rèn)使用 $$hashKey
,比如改為 track by item.id
)
降低渲染數(shù)據(jù)量(比如分頁载佳,或者每次取一小部分?jǐn)?shù)據(jù)炒事,根據(jù)需要再取)
數(shù)據(jù)扁平化(比如對于樹狀結(jié)構(gòu)蔫慧,使用扁平化結(jié)構(gòu)挠乳,構(gòu)建一個 map 和樹狀數(shù)據(jù),對樹操作時姑躲,由于跟扁平數(shù)據(jù)同一引用睡扬,樹狀數(shù)據(jù)變更會同步到原始的扁平數(shù)據(jù))
另外,對于Angular1.x 黍析,存在 臟檢查 和 模塊機(jī)制 的問題卖怜。
移動端
可嘗試 Ionic,但并不完善阐枣。
參考 如何看2015年1月Peter-Paul Koch對Angular的看法马靠?
如何看待 angular 1.2 中引入的 controller as 語法奄抽?
最根本的好處
在 angular 1.2 以前,在 view 上的任何綁定都是直接綁定在 $scope
上的
function myCtrl($scope){ $scope.a = 'aaa'; $scope.foo = function(){ ... }}
使用 controllerAs甩鳄,不需要再注入 $scope
逞度,controller 變成了一個很簡單的 javascript 對象(POJO),一個更純粹的 ViewModel妙啃。
function myCtrl(){ // 使用 vm 捕獲 this 可避免內(nèi)部的函數(shù)在使用 this 時導(dǎo)致上下文改變 var vm = this; vm.a = 'aaa';}
原理
從源碼實(shí)現(xiàn)上來看第晰,controllerAs 語法只是把 controller 這個對象的實(shí)例用 as 別名在 $scope 上創(chuàng)建了一個屬性。
if (directive.controllerAs) { locals.$scope[directive.controllerAs] = controllerInstance;}
但是這樣做彬祖,除了上面提到的使 controller 更加 POJO 外茁瘦,還可以避免遇到 AngularJS 作用域相關(guān)的一個坑(就是上文中 ng-if 產(chǎn)生一級作用域的坑葬馋,其實(shí)也是 javascript 原型鏈繼承中值類型繼承的坑扒怖。因?yàn)槭褂?controllerAs 的話 view 上所有字段都綁定在一個引用的屬性上,比如 vm.xx聋袋,所以坑不再存在)突倍。
{{name}}
問題
使用 controllerAs 會遇到的一個問題是腔稀,因?yàn)闆]有注入 $scope
,導(dǎo)致 $emit
羽历、 $broadcast
焊虏、 $on
、 $watch
等 $scope
下的方法無法使用秕磷。這些跟事件相關(guān)的操作可以封裝起來統(tǒng)一處理诵闭,或者在單個 controller 中引入 $scope
,特殊對待澎嚣。
參考 angular controller as syntax vs scope
詳述 angular 的 “依賴注入”
栗子
依賴注入是一種軟件設(shè)計(jì)模式疏尿,目的是處理代碼之間的依賴關(guān)系,減少組件間的耦合易桃。
舉個栗子褥琐,如果沒有使用 AngularJS,想從后臺查詢數(shù)據(jù)并在前端顯示晤郑,可能需要這樣做:
var animalBox = document.querySelector('.animal-box');var httpRequest = { get: function(url, callback){ console.log(url + ' requested'); var animals = ['cat', 'dog', 'rabbit']; callback(animals); }}var render = function(el, http){ http.get('/api/animals', function(animals){ el.innerHTML = animals; })}render(httpRequest, animalBox);
但是敌呈,如果在調(diào)用 render 的時候不傳參數(shù),像下面這樣造寝,會報錯磕洪,因?yàn)檎也坏?el 和 http(定義的時候依賴了,運(yùn)行的時候不會自動查找依賴項(xiàng))
render();// TypeError: Cannot read property 'get' of undefined
而使用 AngularJS匹舞,可以直接這樣
function myCtrl = ($scope, $http){ $http.get('/api/animals').success(function(data){ $scope.animals = data; })}
也就是說褐鸥,在 Angular App 運(yùn)行的時候,調(diào)用 myCtrl赐稽,自動做了 $scope
和 $http
兩個依賴性的注入叫榕。
原理
AngularJS 是通過構(gòu)造函數(shù)的參數(shù)名字來推斷依賴服務(wù)名稱的浑侥,通過 toString()
來找到這個定義的 function 對應(yīng)的字符串,然后用正則解析出其中的參數(shù)(依賴項(xiàng))晰绎,再去依賴映射中取到對應(yīng)的依賴寓落,實(shí)例化之后傳入。
簡化一下荞下,大概是這樣:
var inject = { // 存儲依賴映射關(guān)系 storage: {}, // 注冊依賴 register: function(name, resource){ this.storage[name] = resource; }, // 解析出依賴并調(diào)用 resolve: function(target){ var self = this; var FN_ARGS = /^function\s[^=XXFN}(\s({FNXX=]))/m; var STRIP_COMMENTS = /((\/\/.$)|(\/*[\s\S]?*\/))/mg; fnText = target.toString().replace(STRIP_COMMENTS, ''); argDecl = fnText.match(FN_ARGS)[1].split(/, ?/g); var args = []; argDecl.forEach(function(arg){ if(self.storage[arg]){ args.push(self.storage[arg]); } }) return function(){ target.apply({}, args); } }}
使用這個 injector伶选,前面那個不用 AngularJS 的栗子這樣改造一下就可以調(diào)用了
inject.register('el', animalBox);inject.register('ajax', httpRequest);render = inject.resolve(render);render();
問題
因?yàn)?AngularJS 的 injector 是假設(shè)函數(shù)的參數(shù)名就是依賴的名字,然后去查找依賴項(xiàng)尖昏,那如果按前面栗子中那樣注入依賴仰税,代碼壓縮后(參數(shù)被重命名了),就無法查找到依賴項(xiàng)了抽诉。
// 壓縮前function myCtrl = ($scope, $http){ ...}// 壓縮后function myCtrl = (a, b){ ...}
所以陨簇,通常會使用下面兩種方式注入依賴(對依賴添加的順序有要求)。
數(shù)組注釋法
myApp.controller('myCtrl', ['$scope', '$http', function($scope, $http){ ...}])
顯式 $inject
myApp.controller('myCtrl', myCtrl);function myCtrl = ($scope, $http){ ...}myCtrl.$inject = ['$scope', '$http'];
29迹淌、補(bǔ)充
對于一個 DI 容器河绽,必須具備三個要素:依賴項(xiàng)的注冊,依賴關(guān)系的聲明和對象的獲取唉窃。
在 AngularJS 中耙饰,module 和 $provide 都可以提供依賴項(xiàng)的注冊;內(nèi)置的 injector 可以獲取對象(自動完成依賴注入)纹份;依賴關(guān)系的聲明苟跪,就是前面問題中提到的那樣。
下面是個栗子
// 對于 module矮嫉,傳遞參數(shù)不止一個削咆,代表新建模塊,空數(shù)組代表不依賴其他模塊// 只有一個參數(shù)(模塊名)蠢笋,代表獲取模塊// 定義 myApp,添加 myApp.services 為其依賴項(xiàng)angular.module('myApp', ['myApp.services']);// 定義一個 services module鳞陨,將 services 都注冊在這個 module 下面angular.module('myApp.services', [])// $provider 有 factory, service, provider, value, constant// 定義一個 HttpServiceangular.module('myApp.services').service('HttpService', ['$http', function($http){ ...}])
30昨寞、參考
[AngularJS] 自己實(shí)現(xiàn)一個簡單的依賴注入
理解angular中的module和injector,即依賴注入
AngularJS中的依賴注入實(shí)際應(yīng)用場景
31厦滤、如何看待angular2
相比 Angular1.x援岩,Angular2的改動很大,幾乎算是一個全新的框架掏导。
基于 TypeScript(可以使用 TypeScript 進(jìn)行開發(fā))享怀,在大型項(xiàng)目團(tuán)隊(duì)協(xié)作時,強(qiáng)語言類型更有利趟咆。
組件化添瓷,提升開發(fā)和維護(hù)的效率梅屉。
還有 module 支持動態(tài)加載,new router鳞贷,promise的原生支持等等坯汤。
迎合未來標(biāo)準(zhǔn),吸納其他框架的優(yōu)點(diǎn)搀愧,值得期待惰聂,不過同時要學(xué)習(xí)的東西也更多了(ES next、TS咱筛、Rx等)搓幌。
參考
浴火重生的Angular
有關(guān)Angular 2.0的一切