angular中常見問答題

一、angularjs的幾大特性是什麼?

雙向數據綁定、依賴注入、模板、指令、MVC/MVVMjavascript

二、列舉幾種常見的設計模式,寫出沒個表明的含義?

MVC :model view controller
MVVM :model view viewModelcss

三、請描述angularjs的運行過程?

angularjs編譯全部的HTML元素標籤,而後在裏面查找angular程序的入口 ng-app 每一個元素上的指令是把全部指令收集起來根據優先級依次編譯html

四、ng-bind和ng-model的區別是什麼?

ng-bind只能展現數據 ng-model能夠操做數據前端

五、請描述$scope的特色還有其最大的父類?

隨建立做用域建立的一個變量,就表明controller所表明的做用域,其持有的對象和方法可在當前及其子做用域生效java

六、原生js的延遲或回調在angularjs裏能完美運行嗎?怎麼解決?能夠用例子?

不能 須要用$apply來進行傳播git

七、{{ array | filter:{‘age’:23}:true }} 這個過濾裏的true是什麼意思?

是否用angular.equals進行比較後爲真才返回程序員

八、自定義過濾建立後返回的是一個什麼對象?

返回一個函數對象 而且函數內要返回最後返回的對象angularjs

九、ng-repeat循環[1,3,2,4,3,4]數組會報錯嗎?若是會怎麼解決?

會由於有重複的內容 track by $indexgithub

十、angular經常使用的服務中value和constant最大的區別是什麼?

constant的建立要早於value 而且其能夠在config配置中使用 value不行ajax

十一、經常使用服務中factory和service的最大區別是什麼?

factory返回的對象當咱們使用它的時候手動初始化並返回,而service是當咱們第一次使用的時候angular幫咱們初始化一次,而後之後使用的時候返回的都是這個對象,factory建立的服務是表明的是其後面函數的返回值,這個返回值能夠是任意類型,service不用返回,直接操做的就是本身

十二、怎麼攔截服務?

在config配置裏注入須要攔截的服務的名字+Provider來攔截

1三、decorator的做用是什麼?和攔截服務的區別是什麼?

裝飾器不只能夠應用在咱們本身的服務上,也能夠對angularjs核心服務進行攔截、中斷甚至替換功能的操做,事實上angularjs的不少測試就是藉助$provide.decorator()創建的、請寫一個配置路由的代碼段(只須要寫怎麼聲明一個路由和其經常使用屬性的代碼段)

1四、resolve的做用是什麼?

若是設置了resolve屬性,angularjs會將列表中的元素都注入到控制器中,列表對象能夠是鍵(鍵值是會被注入到控制器中依賴的名字),也能夠是工廠(便可以是一個服務的名字)

1五、ngRoute默認查找的路由是什麼?$routeProvider.otherwise(’/index’)是什麼做用?

是/ 設置路由的意外指向到/index

1六、$location.path(‘/home’)和$location.url(‘/home’)均可以進行路由跳轉,可是.path方法和.url方法最大的區別是什麼?

.url方法:能夠在跳轉的同時設置查詢串,返回url的整個路徑; 而.path方法:返回的路徑不包括?後面的部分;

1七、什麼是跨域,請簡要描述跨域的場景?

協議 域名 端口號有一個不同就是跨域,也就是不一樣域名之間的訪問;

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

jsonp; post請求設置請求頭 ; jsonp利用的是script能夠訪問外部信息的原理髮送請求而且利用jsonp協議進行數據交互 post設置請求頭跳過預請求來實現跨域

1九、請寫出$http網絡請求的幾種寫法,最少兩種

$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 的區別有哪些?

第一點區別是,ng-if
在後面表達式爲 true 的時候才建立這個 dom 節點,ng-show
是初始時就建立了,用 display:block
和 display:none
來控制顯示和不顯示。
第二點區別是,ng-if
會(隱式地)產生新做用域,ng-switch
、 ng-include
等會動態建立一塊界面的也是如此。
這樣會致使,在 ng-if
中用基本變量綁定 ng-model
,並在外層 div 中把此 model 綁定給另外一個顯示區域,內層改變時,外層不會同步改變,由於此時已是兩個變量了。

{{name}}

<div ng-if="true"> <input type="text" ng-model="name"></div>

2一、ng-show

不存在此問題,由於它不自帶一級做用域。

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

詳見 

AngularJS 中的做用域

2二、ng-repeat迭代數組的時候,若是數組中有相同值,會有什麼問題,如何解決?

會提示 Duplicates in a repeater are not allowed.

加 track by $index

可解決。固然,也能夠 trace by 任何一個普通的值,只要能惟一性標識數組中的每一項便可(創建 dom 和數據之間的關聯)。

ng-click 中寫的表達式,能使用 JS 原生對象上的方法嗎?

不止是 ng-click 中的表達式,只要是在頁面中,都不能直接調用原生的 JS 方法,由於這些並不存在於與頁面對應的 Controller 的 $scope 中。

舉個栗子:

{{parseInt(55.66)}}

會發現,什麼也沒有顯示。
但若是在 $scope 中添加了這個函數:
$scope.parseInt = function(x){ return parseInt(x);}
這樣天然是沒什麼問題了。

2三、對於這種需求,使用一個 filter 或許是不錯的選擇:

{{13.14 | parseIntFilter}}

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

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

這種表達式裏面,豎線和後面的參數經過什麼方式能夠自定義?

filter,格式化數據,接收一個輸入,按某規則處理,返回處理結果。

內置 filter

ng 內置的 filter 有九種:

date(日期)

currency(貨幣)

limitTo(限制數組或字符串長度)

orderBy(排序)

lowercase(小寫)

uppercase(大寫)

number(格式化數字,加上千位分隔符,並接收參數限定小數點位數)

filter(處理一個數組,過濾出含有某個子串的元素)

json(格式化 json 對象)

filter 有兩種使用方法,一種是直接在頁面裏:

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

另外一種是在 js 裏面用:
// $filter('過濾器名稱')(須要過濾的對象, 參數1, 參數2,...)$filter('date')(now, 'yyyy-MM-dd hh:mm:ss');

2四、自定義 filter

// 形式app.filter('過濾器名稱',function(){ return function(須要過濾的對象,過濾器參數1,過濾器參數2,...){ //...作一些事情 return 處理後的對象; }}); // 栗子app.filter('timesFilter', function(){ return function(item, times){ var result = ''; for(var i = 0; i < times; i++){ result += item; } return result; }})

2五、factory、service 和 provider 是什麼關係?

factory

把 service 的方法和數據放在一個對象裏,並返回這個對象

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

service

經過構造函數方式建立 service,返回一個實例化對象

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

provider

建立一個可經過 config 配置的 service,$get 中返回的,就是用 factory 建立 service 的內容

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');});

從底層實現上來看,service 調用了 factory,返回其實例;factory 調用了 provider,返回其 $get
中定義的內容。factory 和 service 功能相似,只不過 factory 是普通 function,能夠返回任何東西(return 的均可以被訪問,因此那些私有變量怎麼寫,你懂的);service 是構造器,能夠不返回(綁定到 this 的均可以被訪問);provider 是增強版 factory,返回一個可配置的 factory。
詳見 AngularJS 之 Factory vs Service vs Provider
angular 的數據綁定採用什麼機制?詳述原理
髒檢查機制。
雙向數據綁定是 AngularJS 的核心機制之一。當 view 中有任何數據變化時,會更新到 model ,當 model 中數據有變化時,view 也會同步更新,顯然,這須要一個監控。
原理就是,Angular 在 scope 模型上設置了一個 監聽隊列,用來監聽數據變化並更新 view 。每次綁定一個東西到 view 上時 AngularJS 就會往 $watch
隊列裏插入一條 $watch
,用來檢測它監視的 model 裏是否有變化的東西。當瀏覽器接收到能夠被 angular context 處理的事件時,$digest
循環就會觸發,遍歷全部的 $watch
,最後更新 dom。
舉個栗子

<button ng-click="val=val+1">increase 1</button>

click 時會產生一次更新的操做(至少觸發兩次 $digest
循環)
按下按鈕

瀏覽器接收到一個事件,進入到 angular context

2六、$digest

循環開始執行,查詢每一個 $watch
是否變化

因爲監視 $scope
.val 的 $watch
報告了變化,所以強制再執行一次 $digest
循環

新的 $digest
循環未檢測到變化

瀏覽器拿回控制器,更新 $scope
.val 新值對應的 dom

$digest
循環的上限是 10 次(超過 10次後拋出一個異常,防止無限循環)。
詳見 關於 AngularJS 的數據綁定
兩個平級界面塊 a 和 b,若是 a 中觸發一個事件,有哪些方式能讓 b 知道?詳述原理
這個問題換一種說法就是,如何在平級界面模塊間進行通訊。有兩種方法,一種是共用服務,一種是基於事件。
共用服務
在 Angular 中,經過 factory 能夠生成一個單例對象,在須要通訊的模塊 a 和 b 中注入這個對象便可。
基於事件
這個又分兩種方式
第一種是藉助父 controller。在子 controller 中向父 controller 觸發($emit
)一個事件,而後在父 controller 中監聽($on
)事件,再廣播($broadcast
)給子 controller ,這樣經過事件攜帶的參數,實現了數據通過父 controller,在同級 controller 之間傳播。
第二種是藉助 $rootScope
。每一個 Angular 應用默認有一個根做用域 $rootScope
, 根做用域位於最頂層,從它往下掛着各級做用域。因此,若是子控制器直接使用 $rootScope
廣播和接收事件,那麼就可實現同級之間的通訊。
詳見 AngularJS 中 Controller 之間的通訊
一個 angular 應用應當如何良好地分層?
目錄結構的劃分
對於小型項目,能夠按照文件類型組織,好比:
cssjs controllers models services filterstemplates

可是對於規模較大的項目,最好按業務模塊劃分,好比:
cssmodules account controllers models services filters templates disk controllers models services filters templates

modules 下最好再有一個 common 目錄來存放公共的東西。
邏輯代碼的拆分
做爲一個 MVVM 框架,Angular 應用自己就應該按照 模型,視圖模型(控制器),視圖來劃分。
這裏邏輯代碼的拆分,主要是指儘可能讓 controller 這一層很薄。提取共用的邏輯到 service 中 (好比後臺數據的請求,數據的共享和緩存,基於事件的模塊間通訊等),提取共用的界面操做到 directive 中(好比將日期選擇、分頁等封裝成組件等),提取共用的格式化操做到 filter 中等等。
在複雜的應用中,也能夠爲實體創建對應的構造函數,好比硬盤(Disk)模塊,可能有列表、新建、詳情這樣幾個視圖,並分別對應的有 controller,那麼能夠建一個 Disk 構造函數,裏面完成數據的增刪改查和驗證操做,有跟 Disk 相關的 controller,就注入 Disk 構造器並生成一個實例,這個實例就具有了增刪改查和驗證方法。這樣既井井有條,又實現了複用(讓 controller 層更薄了)。
參考 AngularJS在蘇寧雲中心的深刻實踐

2七、angular 應用經常使用哪些路由庫,各自的區別是什麼?

Angular1.x 中經常使用 ngRoute 和 ui.router,還有一種爲 Angular2 設計的 new router(面向組件)。後面那個沒在實際項目中用過,就不講了。
不管是 ngRoute 仍是 ui.router,做爲框架額外的附加功能,都必須以 模塊依賴 的形式被引入。
區別
ngRoute 模塊是 Angular 自帶的路由模塊,而 ui.router 模塊是基於 ngRoute模塊開發的第三方模塊。
ui.router 是基於 state (狀態)的, ngRoute 是基於 url 的,ui.router模塊具備更強大的功能,主要體如今視圖的嵌套方面。
使用 ui.router 可以定義有明確父子關係的路由,並經過 ui-view 指令將子路由模版插入到父路由模板的

中去,從而實現視圖嵌套。而在 ngRoute 中不能這樣定義,若是同時在父子視圖中 使用了

會陷入死循環。

示例

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' })

2八、若是經過angular的directive規劃一套全組件化體系,可能遇到哪些挑戰?

沒有本身用 directive 作過一全套組件,講不出。
能想到的一點是,組件如何與外界進行數據的交互,以及如何經過簡單的配置就能使用吧。
分屬不一樣團隊進行開發的 angular 應用,若是要作整合,可能會遇到哪些問題,如何解決?
可能會遇到不一樣模塊之間的衝突。
好比一個團隊全部的開發在 moduleA 下進行,另外一團隊開發的代碼在 moduleB 下

angular.module('myApp.moduleA', []) .factory('serviceA', function(){ ... }) angular.module('myApp.moduleB', []) .factory('serviceA', function(){ ... }) angular.module('myApp', ['myApp.moduleA', 'myApp.moduleB'])

會致使兩個 module 下面的 serviceA 發生了覆蓋。
貌似在 Angular1.x 中並無很好的解決辦法,因此最好在前期進行統一規劃,作好約定,嚴格按照約定開發,每一個開發人員只寫特定區塊代碼。
angular 的缺點有哪些?
強約束
致使學習成本較高,對前端不友好。
但遵照 AngularJS 的約定時,生產力會很高,對 Java 程序員友好。
不利於 SEO
由於全部內容都是動態獲取並渲染生成的,搜索引擎無法爬取。
一種解決辦法是,對於正經常使用戶的訪問,服務器響應 AngularJS 應用的內容;對於搜索引擎的訪問,則響應專門針對 SEO 的HTML頁面。
性能問題
做爲 MVVM 框架,由於實現了數據的雙向綁定,對於大數組、複雜對象會存在性能問題。
能夠用來 優化 Angular 應用的性能 的辦法:
減小監控項(好比對不會變化的數據採用單向綁定)

主動設置索引(指定 track by
,簡單類型默認用自身當索引,對象默認使用 $$hashKey
,好比改成 track by item.id

下降渲染數據量(好比分頁,或者每次取一小部分數據,根據須要再取)

數據扁平化(好比對於樹狀結構,使用扁平化結構,構建一個 map 和樹狀數據,對樹操做時,因爲跟扁平數據同一引用,樹狀數據變動會同步到原始的扁平數據)

另外,對於Angular1.x ,存在 髒檢查 和 模塊機制 的問題。
移動端
可嘗試 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 可避免內部的函數在使用 this 時致使上下文改變 var vm = this; vm.a = 'aaa';}

原理
從源碼實現上來看,controllerAs 語法只是把 controller 這個對象的實例用 as 別名在 $scope 上建立了一個屬性。
if (directive.controllerAs) { locals.$scope[directive.controllerAs] = controllerInstance;}

可是這樣作,除了上面提到的使 controller 更加 POJO 外,還能夠避免遇到 AngularJS 做用域相關的一個坑(就是上文中 ng-if 產生一級做用域的坑,其實也是 javascript 原型鏈繼承中值類型繼承的坑。由於使用 controllerAs 的話 view 上全部字段都綁定在一個引用的屬性上,好比 vm.xx,因此坑再也不存在)。

<div ng-controller="TestCtrl as vm">

{{name}}

<div ng-if="vm.name"> <input type="text" ng-model="vm.name"> </div></div>

問題
使用 controllerAs 會遇到的一個問題是,由於沒有注入 $scope
,致使 $emit
、 $broadcast
、 $on
、 $watch
等 $scope
下的方法沒法使用。這些跟事件相關的操做能夠封裝起來統一處理,或者在單個 controller 中引入 $scope
,特殊對待。
參考 angular controller as syntax vs scope
詳述 angular 的 「依賴注入」
栗子
依賴注入是一種軟件設計模式,目的是處理代碼之間的依賴關係,減小組件間的耦合。
舉個栗子,若是沒有使用 AngularJS,想從後臺查詢數據並在前端顯示,可能須要這樣作:

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);

可是,若是在調用 render 的時候不傳參數,像下面這樣,會報錯,由於找不到 el 和 http(定義的時候依賴了,運行的時候不會自動查找依賴項)
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 運行的時候,調用 myCtrl,自動作了 $scope
和 $http
兩個依賴性的注入。
原理
AngularJS 是經過構造函數的參數名字來推斷依賴服務名稱的,經過 toString()
來找到這個定義的 function 對應的字符串,而後用正則解析出其中的參數(依賴項),再去依賴映射中取到對應的依賴,實例化以後傳入。
簡化一下,大概是這樣:

var inject = { // 存儲依賴映射關係 storage: {}, // 註冊依賴 register: function(name, resource){ this.storage[name] = resource; }, // 解析出依賴並調用 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 的栗子這樣改造一下就能夠調用了

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

問題
由於 AngularJS 的 injector 是假設函數的參數名就是依賴的名字,而後去查找依賴項,那若是按前面栗子中那樣注入依賴,代碼壓縮後(參數被重命名了),就沒法查找到依賴項了。
// 壓縮前function myCtrl = ($scope, $http){ ...}// 壓縮後function myCtrl = (a, b){ ...}

因此,一般會使用下面兩種方式注入依賴(對依賴添加的順序有要求)。
數組註釋法
myApp.controller('myCtrl', ['$scope', '$http', function($scope, $http){ ...}])

顯式 $inject

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

2九、補充

對於一個 DI 容器,必須具有三個要素:依賴項的註冊,依賴關係的聲明和對象的獲取。
在 AngularJS 中,module 和 $provide 均可以提供依賴項的註冊;內置的 injector 能夠獲取對象(自動完成依賴注入);依賴關係的聲明,就是前面問題中提到的那樣。
下面是個栗子
// 對於 module,傳遞參數不止一個,表明新建模塊,空數組表明不依賴其餘模塊// 只有一個參數(模塊名),表明獲取模塊// 定義 myApp,添加 myApp.services 爲其依賴項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] 本身實現一個簡單的依賴注入

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

AngularJS中的依賴注入實際應用場景

3一、如何看待angular2

相比 Angular1.x,Angular2的改動很大,幾乎算是一個全新的框架。
基於 TypeScript(可使用 TypeScript 進行開發),在大型項目團隊協做時,強語言類型更有利。
組件化,提高開發和維護的效率。
還有 module 支持動態加載,new router,promise的原生支持等等。
迎合將來標準,吸納其餘框架的優勢,值得期待,不過同時要學習的東西也更多了(ES next、TS、Rx等)。
參考
浴火重生的Angular

有關Angular 2.0的一切

相關文章
相關標籤/搜索