angular中常見問(wèn)答題

1、angularjs的幾大特性是什么?

雙向數(shù)據(jù)綁定、依賴注入、模板、指令、MVC/MVVM

2、列舉幾種常見的設(shè)計(jì)模式,寫出沒個(gè)代表的含義?

MVC :model view controller

MVVM :model view viewModel

3、請(qǐng)描述angularjs的運(yùn)行過(guò)程?

angularjs編譯所有的HTML元素標(biāo)簽,然后在里面查找angular程序的入口 ng-app 每個(gè)元素上的指令是把所有指令收集起來(lái)根據(jù)優(yōu)先級(jí)依次編譯

4、ng-bind和ng-model的區(qū)別是什么?

ng-bind只能展示數(shù)據(jù) ng-model可以操作數(shù)據(jù)

5、請(qǐng)描述$scope的特點(diǎn)還有其最大的父類?

隨創(chuàng)建作用域創(chuàng)建的一個(gè)變量,就代表controller所代表的作用域,其持有的對(duì)象和方法可在當(dāng)前及其子作用域生效

6、原生js的延遲或回調(diào)在angularjs里能完美運(yùn)行嗎?怎么解決?可以用例子?

不能 需要用$apply來(lái)進(jìn)行傳播

7、{{ array | filter:{‘a(chǎn)ge’:23}:true }} 這個(gè)過(guò)濾里的true是什么意思?

是否用angular.equals進(jìn)行比較后為真才返回

8、自定義過(guò)濾創(chuàng)建后返回的是一個(gè)什么對(duì)象?

返回一個(gè)函數(shù)對(duì)象 并且函數(shù)內(nèi)要返回最后返回的對(duì)象

9、ng-repeat循環(huán)[1,3,2,4,3,4]數(shù)組會(huì)報(bào)錯(cuò)嗎?如果會(huì)怎么解決?

會(huì)因?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返回的對(duì)象當(dāng)我們使用它的時(shí)候手動(dòng)初始化并返回,而service是當(dāng)我們第一次使用的時(shí)候angular幫我們初始化一次,然后以后使用的時(shí)候返回的都是這個(gè)對(duì)象,factory創(chuàng)建的服務(wù)是代表的是其后面函數(shù)的返回值,這個(gè)返回值可以是任意類型,service不用返回,直接操作的就是自己

12、怎么攔截服務(wù)?

在config配置里注入需要攔截的服務(wù)的名字+Provider來(lái)攔截

13、decorator的作用是什么?和攔截服務(wù)的區(qū)別是什么?

裝飾器不僅可以應(yīng)用在我們自己的服務(wù)上,也可以對(duì)angularjs核心服務(wù)進(jìn)行攔截、中斷甚至替換功能的操作,事實(shí)上angularjs的很多測(cè)試就是借助$provide.decorator()建立的、請(qǐng)寫一個(gè)配置路由的代碼段(只需要寫怎么聲明一個(gè)路由和其常用屬性的代碼段)

14、resolve的作用是什么?

如果設(shè)置了resolve屬性,angularjs會(huì)將列表中的元素都注入到控制器中,列表對(duì)象可以是鍵(鍵值是會(huì)被注入到控制器中依賴的名字),也可以是工廠(即可以是一個(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、什么是跨域,請(qǐng)簡(jiǎn)要描述跨域的場(chǎng)景?

協(xié)議 域名 端口號(hào)有一個(gè)不一樣就是跨域,也就是不同域名之間的訪問(wèn);

18、常使用的跨域方案就哪兩種?分別描述其利用的原理?

jsonp; post請(qǐng)求設(shè)置請(qǐng)求頭 ; jsonp利用的是script可以訪問(wèn)外部信息的原理發(fā)送請(qǐng)求并且利用jsonp協(xié)議進(jìn)行數(shù)據(jù)交互 post設(shè)置請(qǐng)求頭跳過(guò)預(yù)請(qǐng)求來(lái)實(shí)現(xiàn)跨域

19、請(qǐng)寫出$http網(wǎng)絡(luò)請(qǐng)求的幾種寫法,最少兩種

$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

來(lái)控制顯示和不顯示。

第二點(diǎn)區(qū)別是,ng-if

會(huì)(隱式地)產(chǎn)生新作用域,ng-switch

、 ng-include

等會(huì)動(dòng)態(tài)創(chuàng)建一塊界面的也是如此。

這樣會(huì)導(dǎo)致,在 ng-if

中用基本變量綁定 ng-model

,并在外層 div 中把此 model 綁定給另一個(gè)顯示區(qū)域,內(nèi)層改變時(shí),外層不會(huì)同步改變,因?yàn)榇藭r(shí)已經(jīng)是兩個(gè)變量了。

{{name}}

#21、ng-show

不存在此問(wèn)題,因?yàn)樗蛔詭б患?jí)作用域。

避免這類問(wèn)題出現(xiàn)的辦法是,始終將頁(yè)面中的元素綁定到對(duì)象的屬性(data.x)而不是直接綁定到基本變量(x)上。

詳見 AngularJS 中的作用域

#22、ng-repeat迭代數(shù)組的時(shí)候,如果數(shù)組中有相同值,會(huì)有什么問(wèn)題,如何解決?

會(huì)提示 Duplicates in a repeater are not allowed.

加 track by $index

可解決。當(dāng)然,也可以 trace by 任何一個(gè)普通的值,只要能唯一性標(biāo)識(shí)數(shù)組中的每一項(xiàng)即可(建立 dom 和數(shù)據(jù)之間的關(guān)聯(lián))。

ng-click 中寫的表達(dá)式,能使用 JS 原生對(duì)象上的方法嗎?

不止是 ng-click 中的表達(dá)式,只要是在頁(yè)面中,都不能直接調(diào)用原生的 JS 方法,因?yàn)檫@些并不存在于與頁(yè)面對(duì)應(yīng)的 Controller 的 $scope 中。

舉個(gè)栗子:

{{parseInt(55.66)}}

會(huì)發(fā)現(xiàn),什么也沒有顯示。

但如果在 $scope 中添加了這個(gè)函數(shù):

$scope.parseInt = function(x){ return parseInt(x);}

這樣自然是沒什么問(wèn)題了。

#23、對(duì)于這種需求,使用一個(gè) filter 或許是不錯(cuò)的選擇:

{{13.14 | parseIntFilter}}

app.filter('parseIntFilter', function(){ return function(item){ return parseInt(item); }})

{{now | 'yyyy-MM-dd'}}

這種表達(dá)式里面,豎線和后面的參數(shù)通過(guò)什么方式可以自定義?

filter,格式化數(shù)據(jù),接收一個(gè)輸入,按某規(guī)則處理,返回處理結(jié)果。

內(nèi)置 filter

ng 內(nèi)置的 filter 有九種:

date(日期)

currency(貨幣)

limitTo(限制數(shù)組或字符串長(zhǎng)度)

orderBy(排序)

lowercase(小寫)

uppercase(大寫)

number(格式化數(shù)字,加上千位分隔符,并接收參數(shù)限定小數(shù)點(diǎn)位數(shù))

filter(處理一個(gè)數(shù)組,過(guò)濾出含有某個(gè)子串的元素)

json(格式化 json 對(duì)象)

filter 有兩種使用方法,一種是直接在頁(yè)面里:

{{now | date : 'yyyy-MM-dd'}}

另一種是在 js 里面用:

// $filter('過(guò)濾器名稱')(需要過(guò)濾的對(duì)象, 參數(shù)1, 參數(shù)2,...)$filter('date')(now, 'yyyy-MM-dd hh:mm:ss');

24、自定義 filter

// 形式app.filter('過(guò)濾器名稱',function(){ return function(需要過(guò)濾的對(duì)象,過(guò)濾器參數(shù)1,過(guò)濾器參數(shù)2,...){ //...做一些事情 ?return 處理后的對(duì)象; }}); // 栗子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è)對(duì)象里,并返回這個(gè)對(duì)象

app.factory('FooService', function(){ return { target: 'factory', sayHello: function(){ return 'hello ' + this.target; } }});

service

通過(guò)構(gòu)造函數(shù)方式創(chuàng)建 service,返回一個(gè)實(shí)例化對(duì)象

app.service('FooService', function(){ var self = this; this.target = 'service'; this.sayHello = function(){ return 'hello ' + self.target; }});

provider

創(chuàng)建一個(gè)可通過(guò) 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)上來(lái)看,service 調(diào)用了 factory,返回其實(shí)例;factory 調(diào)用了 provider,返回其 $get

中定義的內(nèi)容。factory 和 service 功能類似,只不過(guò) factory 是普通 function,可以返回任何東西(return 的都可以被訪問(wèn),所以那些私有變量怎么寫,你懂的);service 是構(gòu)造器,可以不返回(綁定到 this 的都可以被訪問(wèn));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í),會(huì)更新到 model ,當(dāng) model 中數(shù)據(jù)有變化時(shí),view 也會(huì)同步更新,顯然,這需要一個(gè)監(jiān)控。

原理就是,Angular 在 scope 模型上設(shè)置了一個(gè) 監(jiān)聽隊(duì)列,用來(lái)監(jiān)聽數(shù)據(jù)變化并更新 view 。每次綁定一個(gè)東西到 view 上時(shí) AngularJS 就會(huì)往 $watch

隊(duì)列里插入一條 $watch

,用來(lái)檢測(cè)它監(jiān)視的 model 里是否有變化的東西。當(dāng)瀏覽器接收到可以被 angular context 處理的事件時(shí),$digest

循環(huán)就會(huì)觸發(fā),遍歷所有的 $watch

,最后更新 dom。

舉個(gè)栗子

increase 1

click 時(shí)會(huì)產(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)未檢測(cè)到變化

瀏覽器拿回控制器,更新 $scope

.val 新值對(duì)應(yīng)的 dom

$digest

循環(huán)的上限是 10 次(超過(guò) 10次后拋出一個(gè)異常,防止無(wú)限循環(huán))。

詳見 關(guān)于 AngularJS 的數(shù)據(jù)綁定

兩個(gè)平級(jí)界面塊 a 和 b,如果 a 中觸發(fā)一個(gè)事件,有哪些方式能讓 b 知道?詳述原理

這個(gè)問(wèn)題換一種說(shuō)法就是,如何在平級(jí)界面模塊間進(jìn)行通信。有兩種方法,一種是共用服務(wù),一種是基于事件。

共用服務(wù)

在 Angular 中,通過(guò) factory 可以生成一個(gè)單例對(duì)象,在需要通信的模塊 a 和 b 中注入這個(gè)對(duì)象即可。

基于事件

這個(gè)又分兩種方式

第一種是借助父 controller。在子 controller 中向父 controller 觸發(fā)($emit

)一個(gè)事件,然后在父 controller 中監(jiān)聽($on

)事件,再?gòu)V播($broadcast

)給子 controller ,這樣通過(guò)事件攜帶的參數(shù),實(shí)現(xiàn)了數(shù)據(jù)經(jīng)過(guò)父 controller,在同級(jí) controller 之間傳播。

第二種是借助 $rootScope

。每個(gè) Angular 應(yīng)用默認(rèn)有一個(gè)根作用域 $rootScope

, 根作用域位于最頂層,從它往下掛著各級(jí)作用域。所以,如果子控制器直接使用 $rootScope

廣播和接收事件,那么就可實(shí)現(xiàn)同級(jí)之間的通信。

詳見 AngularJS 中 Controller 之間的通信

一個(gè) angular 應(yīng)用應(yīng)當(dāng)如何良好地分層?

目錄結(jié)構(gòu)的劃分

對(duì)于小型項(xiàng)目,可以按照文件類型組織,比如:

cssjs controllers models services filterstemplates

但是對(duì)于規(guī)模較大的項(xiàng)目,最好按業(yè)務(wù)模塊劃分,比如:

cssmodules account controllers models services filters templates disk controllers models services filters templates

modules 下最好再有一個(gè) common 目錄來(lái)存放公共的東西。

邏輯代碼的拆分

作為一個(gè) MVVM 框架,Angular 應(yīng)用本身就應(yīng)該按照 模型,視圖模型(控制器),視圖來(lái)劃分。

這里邏輯代碼的拆分,主要是指盡量讓 controller 這一層很薄。提取共用的邏輯到 service 中 (比如后臺(tái)數(shù)據(jù)的請(qǐng)求,數(shù)據(jù)的共享和緩存,基于事件的模塊間通信等),提取共用的界面操作到 directive 中(比如將日期選擇、分頁(yè)等封裝成組件等),提取共用的格式化操作到 filter 中等等。

在復(fù)雜的應(yīng)用中,也可以為實(shí)體建立對(duì)應(yīng)的構(gòu)造函數(shù),比如硬盤(Disk)模塊,可能有列表、新建、詳情這樣幾個(gè)視圖,并分別對(duì)應(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)用常用哪些路由庫(kù),各自的區(qū)別是什么?

Angular1.x 中常用 ngRoute 和 ui.router,還有一種為 Angular2 設(shè)計(jì)的 new router(面向組件)。后面那個(gè)沒在實(shí)際項(xiàng)目中用過(guò),就不講了。

無(wú)論是 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)系的路由,并通過(guò) ui-view 指令將子路由模版插入到父路由模板的

中去,從而實(shí)現(xiàn)視圖嵌套。而在 ngRoute 中不能這樣定義,如果同時(shí)在父子視圖中 使用了

會(huì)陷入死循環(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、如果通過(guò)angular的directive規(guī)劃一套全組件化體系,可能遇到哪些挑戰(zhàn)?

沒有自己用 directive 做過(guò)一全套組件,講不出。

能想到的一點(diǎn)是,組件如何與外界進(jìn)行數(shù)據(jù)的交互,以及如何通過(guò)簡(jiǎn)單的配置就能使用吧。

分屬不同團(tuán)隊(duì)進(jìn)行開發(fā)的 angular 應(yīng)用,如果要做整合,可能會(huì)遇到哪些問(wèn)題,如何解決?

可能會(huì)遇到不同模塊之間的沖突。

比如一個(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'])

會(huì)導(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í)成本較高,對(duì)前端不友好。

但遵守 AngularJS 的約定時(shí),生產(chǎn)力會(huì)很高,對(duì) Java 程序員友好。

不利于 SEO

因?yàn)樗袃?nèi)容都是動(dòng)態(tài)獲取并渲染生成的,搜索引擎沒法爬取。

一種解決辦法是,對(duì)于正常用戶的訪問(wèn),服務(wù)器響應(yīng) AngularJS 應(yīng)用的內(nèi)容;對(duì)于搜索引擎的訪問(wèn),則響應(yīng)專門針對(duì) SEO 的HTML頁(yè)面。

性能問(wèn)題

作為 MVVM 框架,因?yàn)閷?shí)現(xiàn)了數(shù)據(jù)的雙向綁定,對(duì)于大數(shù)組、復(fù)雜對(duì)象會(huì)存在性能問(wèn)題。

可以用來(lái) 優(yōu)化 Angular 應(yīng)用的性能 的辦法:

減少監(jiān)控項(xiàng)(比如對(duì)不會(huì)變化的數(shù)據(jù)采用單向綁定)

主動(dòng)設(shè)置索引(指定 track by

,簡(jiǎn)單類型默認(rèn)用自身當(dāng)索引,對(duì)象默認(rèn)使用 $$hashKey

,比如改為 track by item.id

降低渲染數(shù)據(jù)量(比如分頁(yè),或者每次取一小部分?jǐn)?shù)據(jù),根據(jù)需要再取)

數(shù)據(jù)扁平化(比如對(duì)于樹狀結(jié)構(gòu),使用扁平化結(jié)構(gòu),構(gòu)建一個(gè) map 和樹狀數(shù)據(jù),對(duì)樹操作時(shí),由于跟扁平數(shù)據(jù)同一引用,樹狀數(shù)據(jù)變更會(huì)同步到原始的扁平數(shù)據(jù))

另外,對(duì)于Angular1.x ,存在 臟檢查 和 模塊機(jī)制 的問(wèn)題。

移動(dòng)端

可嘗試 Ionic,但并不完善。

參考 如何看2015年1月Peter-Paul Koch對(duì)Angular的看法?

如何看待 angular 1.2 中引入的 controller as 語(yǔ)法?

最根本的好處

在 angular 1.2 以前,在 view 上的任何綁定都是直接綁定在 $scope

上的

function myCtrl($scope){ $scope.a = 'aaa'; $scope.foo = function(){ ... }}

使用 controllerAs,不需要再注入 $scope

,controller 變成了一個(gè)很簡(jiǎn)單的 javascript 對(duì)象(POJO),一個(gè)更純粹的 ViewModel。

function myCtrl(){ // 使用 vm 捕獲 this 可避免內(nèi)部的函數(shù)在使用 this 時(shí)導(dǎo)致上下文改變 var vm = this; vm.a = 'aaa';}

原理

從源碼實(shí)現(xiàn)上來(lái)看,controllerAs 語(yǔ)法只是把 controller 這個(gè)對(duì)象的實(shí)例用 as 別名在 $scope 上創(chuàng)建了一個(gè)屬性。

if (directive.controllerAs) { locals.$scope[directive.controllerAs] = controllerInstance;}

但是這樣做,除了上面提到的使 controller 更加 POJO 外,還可以避免遇到 AngularJS 作用域相關(guān)的一個(gè)坑(就是上文中 ng-if 產(chǎn)生一級(jí)作用域的坑,其實(shí)也是 javascript 原型鏈繼承中值類型繼承的坑。因?yàn)槭褂?controllerAs 的話 view 上所有字段都綁定在一個(gè)引用的屬性上,比如 vm.xx,所以坑不再存在)。

{{name}}

?

問(wèn)題

使用 controllerAs 會(huì)遇到的一個(gè)問(wèn)題是,因?yàn)闆]有注入 $scope

,導(dǎo)致 $emit

、 $broadcast

、 $on

、 $watch

等 $scope

下的方法無(wú)法使用。這些跟事件相關(guān)的操作可以封裝起來(lái)統(tǒng)一處理,或者在單個(gè) controller 中引入 $scope

,特殊對(duì)待。

參考 angular controller as syntax vs scope

詳述 angular 的 “依賴注入”

栗子

依賴注入是一種軟件設(shè)計(jì)模式,目的是處理代碼之間的依賴關(guān)系,減少組件間的耦合。

舉個(gè)栗子,如果沒有使用 AngularJS,想從后臺(tái)查詢數(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ù),像下面這樣,會(huì)報(bào)錯(cuò),因?yàn)檎也坏?el 和 http(定義的時(shí)候依賴了,運(yùn)行的時(shí)候不會(huì)自動(dòng)查找依賴項(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; })}

也就是說(shuō),在 Angular App 運(yùn)行的時(shí)候,調(diào)用 myCtrl,自動(dòng)做了 $scope

和 $http

兩個(gè)依賴性的注入。

原理

AngularJS 是通過(guò)構(gòu)造函數(shù)的參數(shù)名字來(lái)推斷依賴服務(wù)名稱的,通過(guò) toString()

來(lái)找到這個(gè)定義的 function 對(duì)應(yīng)的字符串,然后用正則解析出其中的參數(shù)(依賴項(xiàng)),再去依賴映射中取到對(duì)應(yīng)的依賴,實(shí)例化之后傳入。

簡(jiǎn)化一下,大概是這樣:

var inject = { // 存儲(chǔ)依賴映射關(guān)系 storage: {}, // 注冊(cè)依賴 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); } }}

使用這個(gè) injector,前面那個(gè)不用 AngularJS 的栗子這樣改造一下就可以調(diào)用了

inject.register('el', animalBox);inject.register('ajax', httpRequest);render = inject.resolve(render);render();

問(wèn)題

因?yàn)?AngularJS 的 injector 是假設(shè)函數(shù)的參數(shù)名就是依賴的名字,然后去查找依賴項(xiàng),那如果按前面栗子中那樣注入依賴,代碼壓縮后(參數(shù)被重命名了),就無(wú)法查找到依賴項(xiàng)了。

// 壓縮前function myCtrl = ($scope, $http){ ...}// 壓縮后function myCtrl = (a, b){ ...}

所以,通常會(huì)使用下面兩種方式注入依賴(對(duì)依賴添加的順序有要求)。

數(shù)組注釋法

myApp.controller('myCtrl', ['$scope', '$http', function($scope, $http){ ...}])

顯式 $inject

myApp.controller('myCtrl', myCtrl);function myCtrl = ($scope, $http){ ...}myCtrl.$inject = ['$scope', '$http'];

29、補(bǔ)充

對(duì)于一個(gè) DI 容器,必須具備三個(gè)要素:依賴項(xiàng)的注冊(cè),依賴關(guān)系的聲明和對(duì)象的獲取。

在 AngularJS 中,module 和 $provide 都可以提供依賴項(xiàng)的注冊(cè);內(nèi)置的 injector 可以獲取對(duì)象(自動(dòng)完成依賴注入);依賴關(guān)系的聲明,就是前面問(wèn)題中提到的那樣。

下面是個(gè)栗子

// 對(duì)于 module,傳遞參數(shù)不止一個(gè),代表新建模塊,空數(shù)組代表不依賴其他模塊// 只有一個(gè)參數(shù)(模塊名),代表獲取模塊// 定義 myApp,添加 myApp.services 為其依賴項(xiàng)angular.module('myApp', ['myApp.services']);// 定義一個(gè) services module,將 services 都注冊(cè)在這個(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è)簡(jiǎn)單的依賴注入

理解angular中的module和injector,即依賴注入

AngularJS中的依賴注入實(shí)際應(yīng)用場(chǎng)景

31、如何看待angular2

相比 Angular1.x,Angular2的改動(dòng)很大,幾乎算是一個(gè)全新的框架。

基于 TypeScript(可以使用 TypeScript 進(jìn)行開發(fā)),在大型項(xiàng)目團(tuán)隊(duì)協(xié)作時(shí),強(qiáng)語(yǔ)言類型更有利。

組件化,提升開發(fā)和維護(hù)的效率。

還有 module 支持動(dòng)態(tài)加載,new router,promise的原生支持等等。

迎合未來(lái)標(biāo)準(zhǔn),吸納其他框架的優(yōu)點(diǎn),值得期待,不過(guò)同時(shí)要學(xué)習(xí)的東西也更多了(ES next、TS、Rx等)。

參考

浴火重生的Angular

有關(guān)Angular 2.0的一切

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容