1、angularjs的幾大特性是什么?
雙向數(shù)據(jù)綁定、依賴注入、模板、指令、MVC/MVVM
2、列舉幾種常見的設(shè)計(jì)模式,寫出沒個(gè)代表的含義?
MVC :model view controller
MVVM :model view viewModel
3、請描述angularjs的運(yùn)行過程?
angularjs編譯所有的HTML元素標(biāo)簽,然后在里面查找angular程序的入口 ng-app 每個(gè)元素上的指令是把所有指令收集起來根據(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)建的一個(gè)變量,就代表controller所代表的作用域,其持有的對象和方法可在當(dāng)前及其子作用域生效
6、原生js的延遲或回調(diào)在angularjs里能完美運(yùn)行嗎?怎么解決?可以用例子?
不能 需要用$apply來進(jìn)行傳播
7、{{ array | filter:{‘a(chǎn)ge’:23}:true }} 這個(gè)過濾里的true是什么意思?
是否用angular.equals進(jìn)行比較后為真才返回
8、自定義過濾創(chuàng)建后返回的是一個(gè)什么對象?
返回一個(gè)函數(shù)對象 并且函數(shù)內(nèi)要返回最后返回的對象
9、ng-repeat循環(huán)[1,3,2,4,3,4]數(shù)組會報(bào)錯(cuò)嗎?如果會怎么解決?
會因?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)我們使用它的時(shí)候手動初始化并返回,而service是當(dāng)我們第一次使用的時(shí)候angular幫我們初始化一次,然后以后使用的時(shí)候返回的都是這個(gè)對象,factory創(chuàng)建的服務(wù)是代表的是其后面函數(shù)的返回值,這個(gè)返回值可以是任意類型,service不用返回,直接操作的就是自己
12、怎么攔截服務(wù)?
在config配置里注入需要攔截的服務(wù)的名字+Provider來攔截
13、decorator的作用是什么?和攔截服務(wù)的區(qū)別是什么?
裝飾器不僅可以應(yīng)用在我們自己的服務(wù)上,也可以對angularjs核心服務(wù)進(jìn)行攔截、中斷甚至替換功能的操作,事實(shí)上angularjs的很多測試就是借助$provide.decorator()建立的、請寫一個(gè)配置路由的代碼段(只需要寫怎么聲明一個(gè)路由和其常用屬性的代碼段)
14、resolve的作用是什么?
如果設(shè)置了resolve屬性,angularjs會將列表中的元素都注入到控制器中,列表對象可以是鍵(鍵值是會被注入到控制器中依賴的名字),也可以是工廠(即可以是一個(gè)服務(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í)設(shè)置查詢串,返回url的整個(gè)路徑; 而.path方法:返回的路徑不包括?后面的部分;
17、什么是跨域,請簡要描述跨域的場景?
協(xié)議 域名 端口號有一個(gè)不一樣就是跨域,也就是不同域名之間的訪問;
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 的時(shí)候才創(chuàng)建這個(gè) dom 節(jié)點(diǎn),ng-show
是初始時(shí)就創(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 綁定給另一個(gè)顯示區(qū)域,內(nèi)層改變時(shí),外層不會同步改變,因?yàn)榇藭r(shí)已經(jīng)是兩個(gè)變量了。
<p>{{name}}</p><div ng-if="true"> <input type="text" ng-model="name"></div>
21、ng-show
不存在此問題,因?yàn)樗蛔詭б患壸饔糜颉?br>
避免這類問題出現(xiàn)的辦法是,始終將頁面中的元素綁定到對象的屬性(data.x)而不是直接綁定到基本變量(x)上。
詳見 AngularJS 中的作用域
22、ng-repeat迭代數(shù)組的時(shí)候,如果數(shù)組中有相同值,會有什么問題,如何解決?
會提示 Duplicates in a repeater are not allowed.
加 track by $index
可解決。當(dāng)然,也可以 trace by 任何一個(gè)普通的值,只要能唯一性標(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 中。
舉個(gè)栗子:
<p>{{parseInt(55.66)}}<p>
會發(fā)現(xiàn),什么也沒有顯示。
但如果在 $scope 中添加了這個(gè)函數(shù):
$scope.parseInt = function(x){ return parseInt(x);}
這樣自然是沒什么問題了。
23、對于這種需求,使用一個(gè) filter 或許是不錯(cuò)的選擇:
<p>{{13.14 | parseIntFilter}}</p>app.filter('parseIntFilter', function(){ return function(item){ return parseInt(item); }})
{{now | 'yyyy-MM-dd'}}
這種表達(dá)式里面,豎線和后面的參數(shù)通過什么方式可以自定義?
filter,格式化數(shù)據(jù),接收一個(gè)輸入,按某規(guī)則處理,返回處理結(jié)果。
內(nèi)置 filter
ng 內(nèi)置的 filter 有九種:
date(日期)
currency(貨幣)
limitTo(限制數(shù)組或字符串長度)
orderBy(排序)
lowercase(小寫)
uppercase(大寫)
number(格式化數(shù)字,加上千位分隔符,并接收參數(shù)限定小數(shù)點(diǎn)位數(shù))
filter(處理一個(gè)數(shù)組,過濾出含有某個(gè)子串的元素)
json(格式化 json 對象)
filter 有兩種使用方法,一種是直接在頁面里:
<p>{{now | date : 'yyyy-MM-dd'}}</p>
另一種是在 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ù)放在一個(gè)對象里,并返回這個(gè)對象
app.factory('FooService', function(){ return { target: 'factory', sayHello: function(){ return 'hello ' + this.target; } }});
service
通過構(gòu)造函數(shù)方式創(chuàng)建 service,返回一個(gè)實(shí)例化對象
app.service('FooService', function(){ var self = this; this.target = 'service'; this.sayHello = function(){ return 'hello ' + self.target; }});
provider
創(chuàng)建一個(gè)可通過 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,返回一個(gè)可配置的 factory。
詳見 AngularJS 之 Factory vs Service vs Provider
angular 的數(shù)據(jù)綁定采用什么機(jī)制?詳述原理
臟檢查機(jī)制。
雙向數(shù)據(jù)綁定是 AngularJS 的核心機(jī)制之一。當(dāng) view 中有任何數(shù)據(jù)變化時(shí),會更新到 model ,當(dāng) model 中數(shù)據(jù)有變化時(shí),view 也會同步更新,顯然,這需要一個(gè)監(jiān)控。
原理就是,Angular 在 scope 模型上設(shè)置了一個(gè) 監(jiān)聽隊(duì)列,用來監(jiān)聽數(shù)據(jù)變化并更新 view 。每次綁定一個(gè)東西到 view 上時(shí) AngularJS 就會往 $watch
隊(duì)列里插入一條 $watch
,用來檢測它監(jiān)視的 model 里是否有變化的東西。當(dāng)瀏覽器接收到可以被 angular context 處理的事件時(shí),$digest
循環(huán)就會觸發(fā),遍歷所有的 $watch
,最后更新 dom。
舉個(gè)栗子
<button ng-click="val=val+1">increase 1</button>
click 時(shí)會產(chǎn)生一次更新的操作(至少觸發(fā)兩次 $digest
循環(huán))
按下按鈕
瀏覽器接收到一個(gè)事件,進(jìn)入到 angular context
26、$digest
循環(huán)開始執(zhí)行,查詢每個(gè) $watch
是否變化
由于監(jiān)視 $scope
.val 的 $watch
報(bào)告了變化,因此強(qiáng)制再執(zhí)行一次 $digest
循環(huán)
新的 $digest
循環(huán)未檢測到變化
瀏覽器拿回控制器,更新 $scope
.val 新值對應(yīng)的 dom
$digest
循環(huán)的上限是 10 次(超過 10次后拋出一個(gè)異常,防止無限循環(huán))。
詳見 關(guān)于 AngularJS 的數(shù)據(jù)綁定
兩個(gè)平級界面塊 a 和 b,如果 a 中觸發(fā)一個(gè)事件,有哪些方式能讓 b 知道?詳述原理
這個(gè)問題換一種說法就是,如何在平級界面模塊間進(jìn)行通信。有兩種方法,一種是共用服務(wù),一種是基于事件。
共用服務(wù)
在 Angular 中,通過 factory 可以生成一個(gè)單例對象,在需要通信的模塊 a 和 b 中注入這個(gè)對象即可。
基于事件
這個(gè)又分兩種方式
第一種是借助父 controller。在子 controller 中向父 controller 觸發(fā)($emit
)一個(gè)事件,然后在父 controller 中監(jiān)聽($on
)事件,再廣播($broadcast
)給子 controller ,這樣通過事件攜帶的參數(shù),實(shí)現(xiàn)了數(shù)據(jù)經(jīng)過父 controller,在同級 controller 之間傳播。
第二種是借助 $rootScope
。每個(gè) Angular 應(yīng)用默認(rèn)有一個(gè)根作用域 $rootScope
, 根作用域位于最頂層,從它往下掛著各級作用域。所以,如果子控制器直接使用 $rootScope
廣播和接收事件,那么就可實(shí)現(xiàn)同級之間的通信。
詳見 AngularJS 中 Controller 之間的通信
一個(gè) 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 下最好再有一個(gè) common 目錄來存放公共的東西。
邏輯代碼的拆分
作為一個(gè) MVVM 框架,Angular 應(yīng)用本身就應(yīng)該按照 模型,視圖模型(控制器),視圖來劃分。
這里邏輯代碼的拆分,主要是指盡量讓 controller 這一層很薄。提取共用的邏輯到 service 中 (比如后臺數(shù)據(jù)的請求,數(shù)據(jù)的共享和緩存,基于事件的模塊間通信等),提取共用的界面操作到 directive 中(比如將日期選擇、分頁等封裝成組件等),提取共用的格式化操作到 filter 中等等。
在復(fù)雜的應(yīng)用中,也可以為實(shí)體建立對應(yīng)的構(gòu)造函數(shù),比如硬盤(Disk)模塊,可能有列表、新建、詳情這樣幾個(gè)視圖,并分別對應(yīng)的有 controller,那么可以建一個(gè) Disk 構(gòu)造函數(shù),里面完成數(shù)據(jù)的增刪改查和驗(yàn)證操作,有跟 Disk 相關(guān)的 controller,就注入 Disk 構(gòu)造器并生成一個(gè)實(shí)例,這個(gè)實(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(面向組件)。后面那個(gè)沒在實(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 指令將子路由模版插入到父路由模板的 <div ui-view></div>
中去,從而實(shí)現(xiàn)視圖嵌套。而在 ngRoute 中不能這樣定義,如果同時(shí)在父子視圖中 使用了 <div ng-view></div>
會陷入死循環(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)用,如果要做整合,可能會遇到哪些問題,如何解決?
可能會遇到不同模塊之間的沖突。
比如一個(gè)團(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)致兩個(gè) module 下面的 serviceA 發(fā)生了覆蓋。
貌似在 Angular1.x 中并沒有很好的解決辦法,所以最好在前期進(jìn)行統(tǒng)一規(guī)劃,做好約定,嚴(yán)格按照約定開發(fā),每個(gè)開發(fā)人員只寫特定區(qū)塊代碼。
angular 的缺點(diǎn)有哪些?
強(qiáng)約束
導(dǎo)致學(xué)習(xí)成本較高,對前端不友好。
但遵守 AngularJS 的約定時(shí),生產(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ù)需要再?。?/p>
數(shù)據(jù)扁平化(比如對于樹狀結(jié)構(gòu),使用扁平化結(jié)構(gòu),構(gòu)建一個(gè) map 和樹狀數(shù)據(jù),對樹操作時(shí),由于跟扁平數(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 變成了一個(gè)很簡單的 javascript 對象(POJO),一個(gè)更純粹的 ViewModel。
function myCtrl(){ // 使用 vm 捕獲 this 可避免內(nèi)部的函數(shù)在使用 this 時(shí)導(dǎo)致上下文改變 var vm = this; vm.a = 'aaa';}
原理
從源碼實(shí)現(xiàn)上來看,controllerAs 語法只是把 controller 這個(gè)對象的實(shí)例用 as 別名在 $scope 上創(chuàng)建了一個(gè)屬性。
if (directive.controllerAs) { locals.$scope[directive.controllerAs] = controllerInstance;}
但是這樣做,除了上面提到的使 controller 更加 POJO 外,還可以避免遇到 AngularJS 作用域相關(guān)的一個(gè)坑(就是上文中 ng-if 產(chǎn)生一級作用域的坑,其實(shí)也是 javascript 原型鏈繼承中值類型繼承的坑。因?yàn)槭褂?controllerAs 的話 view 上所有字段都綁定在一個(gè)引用的屬性上,比如 vm.xx,所以坑不再存在)。
<div ng-controller="TestCtrl as vm"> <p>{{name}}</p> <div ng-if="vm.name"> <input type="text" ng-model="vm.name"> </div></div>
問題
使用 controllerAs 會遇到的一個(gè)問題是,因?yàn)闆]有注入 $scope
,導(dǎo)致 $emit
、 $broadcast
、 $on
、 $watch
等 $scope
下的方法無法使用。這些跟事件相關(guān)的操作可以封裝起來統(tǒng)一處理,或者在單個(gè) controller 中引入 $scope
,特殊對待。
參考 angular controller as syntax vs scope
詳述 angular 的 “依賴注入”
栗子
依賴注入是一種軟件設(shè)計(jì)模式,目的是處理代碼之間的依賴關(guān)系,減少組件間的耦合。
舉個(gè)栗子,如果沒有使用 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í)候不傳參數(shù),像下面這樣,會報(bào)錯(cuò),因?yàn)檎也坏?el 和 http(定義的時(shí)候依賴了,運(yùn)行的時(shí)候不會自動查找依賴項(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)行的時(shí)候,調(diào)用 myCtrl,自動做了 $scope
和 $http
兩個(gè)依賴性的注入。
原理
AngularJS 是通過構(gòu)造函數(shù)的參數(shù)名字來推斷依賴服務(wù)名稱的,通過 toString()
來找到這個(gè)定義的 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*[(](\s([^)]))/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); } }}
使用這個(gè) injector,前面那個(gè)不用 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ǔ)充
對于一個(gè) DI 容器,必須具備三個(gè)要素:依賴項(xiàng)的注冊,依賴關(guān)系的聲明和對象的獲取。
在 AngularJS 中,module 和 $provide 都可以提供依賴項(xiàng)的注冊;內(nèi)置的 injector 可以獲取對象(自動完成依賴注入);依賴關(guān)系的聲明,就是前面問題中提到的那樣。
下面是個(gè)栗子
// 對于 module,傳遞參數(shù)不止一個(gè),代表新建模塊,空數(shù)組代表不依賴其他模塊// 只有一個(gè)參數(shù)(模塊名),代表獲取模塊// 定義 myApp,添加 myApp.services 為其依賴項(xiàng)angular.module('myApp', ['myApp.services']);// 定義一個(gè) services module,將 services 都注冊在這個(gè) module 下面angular.module('myApp.services', [])// $provider 有 factory, service, provider, value, constant// 定義一個(gè) HttpServiceangular.module('myApp.services').service('HttpService', ['$http', function($http){ ...}])
30、參考
[AngularJS] 自己實(shí)現(xiàn)一個(gè)簡單的依賴注入
理解angular中的module和injector,即依賴注入
AngularJS中的依賴注入實(shí)際應(yīng)用場景
31、如何看待angular2
相比 Angular1.x,Angular2的改動很大,幾乎算是一個(gè)全新的框架。
基于 TypeScript(可以使用 TypeScript 進(jìn)行開發(fā)),在大型項(xiàng)目團(tuán)隊(duì)協(xié)作時(shí),強(qiáng)語言類型更有利。
組件化,提升開發(fā)和維護(hù)的效率。
還有 module 支持動態(tài)加載,new router,promise的原生支持等等。
迎合未來標(biāo)準(zhǔn),吸納其他框架的優(yōu)點(diǎn),值得期待,不過同時(shí)要學(xué)習(xí)的東西也更多了(ES next、TS、Rx等)。
參考
浴火重生的Angular