angular之中晦款,$scope $rootScope $watch $state 是什么炎功?


1.背景介紹

1、AngularJS Scope(作用域)

Scope(作用域)是應(yīng)用在 HTML (視圖)和 JavaScript (控制器)之間的紐帶柬赐。Scope是一個(gè)對(duì)象亡问,有可用的方法和屬性。Scope可應(yīng)用在視圖和控制器上肛宋。$scope的使用貫穿整個(gè) Angular App應(yīng)用,它與數(shù)據(jù)模型相關(guān)聯(lián),同時(shí)也是表達(dá)式執(zhí)行的上下文.有了 $scope就在視圖和控制器之間建立了一個(gè)通道,基于作用域視圖在修改數(shù)據(jù)時(shí)會(huì)立刻更新 $scope,同樣的 $scope發(fā)生改變時(shí)也會(huì)立刻重新渲染視圖.

2州藕、根作用域 rootScope

所有的應(yīng)用都有一個(gè) $rootScope,它可以作用在 ng-app指令包含的所有 HTML元素中酝陈。$rootScope可作用于整個(gè)應(yīng)用中床玻。是各個(gè) controller中 scope的橋梁。用 rootscope定義的值沉帮,可以在各個(gè) controller中使用

2.知識(shí)剖析

? ? ? 1锈死、$scope

$scope是一個(gè)把view(一個(gè)DOM元素)連結(jié)到controller上的對(duì)象。在我們的MVC結(jié)構(gòu)里穆壕,這個(gè) $scope將成為model待牵,它提供一個(gè)綁定到DOM元素(以及其子元素)上的excecution context。


$scope實(shí)際上就是一個(gè)JavaScript對(duì)象喇勋,controller和view都可以訪問(wèn)它缨该,所以我們可以利用它在兩者間傳遞信息。在這個(gè) $scope對(duì)象里川背,我們既可以存儲(chǔ)數(shù)據(jù)贰拿,又可以存儲(chǔ)將要運(yùn)行在view上的函數(shù)。每一個(gè)Angular應(yīng)用都會(huì)有一個(gè)$rootScope熄云。這個(gè)$rootScope 是最頂級(jí)的scope膨更,它對(duì)應(yīng)著含有ng-app 指令屬性的那個(gè)DOM元素。如果頁(yè)面上沒(méi)有明確設(shè)定$scope 缴允,Angular 就會(huì)把數(shù)據(jù)和函數(shù)都綁定到這里荚守。

Angular應(yīng)用啟動(dòng)并生成視圖時(shí),會(huì)將根 ng-app元素與 $rootScope進(jìn)行綁定.$rootScope是所有 $scope的最上層對(duì)象,可以理解為一個(gè) Angular應(yīng)用中得全局作用域?qū)ο?所以不應(yīng)該附加太多邏輯或者變量給$rootScope,和污染 Javascript全局作用域是一樣的道理.

$scope的作用

$scope對(duì)象在 Angular中充當(dāng)數(shù)據(jù)模型的作用,也就是一般 MVC框架中 Model得角色.但又不完全與通常意義上的數(shù)據(jù)模型一樣,因?yàn)?$scope并不處理和操作數(shù)據(jù),它只是建立了視圖和 HTML之間的橋梁,讓視圖和 Controller之間可以友好的通訊。

它有如下作用和功能:

提供了觀察者可以監(jiān)聽數(shù)據(jù)模型的變化

可以將數(shù)據(jù)模型的變化通知給整個(gè) App

可以進(jìn)行嵌套,隔離業(yè)務(wù)功能和數(shù)據(jù)

給表達(dá)式提供上下文執(zhí)行環(huán)境

在 Javascript中創(chuàng)建一個(gè)新的執(zhí)行上下文,實(shí)際就是用函數(shù)創(chuàng)建了一個(gè)新的本地上下文,

在 Angular中當(dāng)為子 DOM元素創(chuàng)建新的作用域時(shí),其實(shí)就是為子 DOM元素創(chuàng)建了一個(gè)新的執(zhí)行上下文.

$scope的生命周期有4個(gè)階段:

1.創(chuàng)建

控制器或者指令創(chuàng)建時(shí), Angular會(huì)使用 $injector創(chuàng)建一個(gè)新的作用域,然后在控制器或指令運(yùn)行時(shí),將作用域傳遞進(jìn)去.

2.鏈接

Angular啟動(dòng)后會(huì)將所有 $scope對(duì)象附加或者說(shuō)鏈接到視圖上,所有創(chuàng)建 $scope對(duì)象的函數(shù)也會(huì)被附加到視圖上.

這些作用域?qū)?huì)注冊(cè)當(dāng) Angular上下文發(fā)生變化時(shí)需要運(yùn)行的函數(shù).也就是 $watch函數(shù), Angular通過(guò)這些函數(shù)或者何時(shí)開始事件循環(huán).

3.更新

一旦事件循環(huán)開始運(yùn)行,就會(huì)開始執(zhí)行自己的臟值檢測(cè).一旦檢測(cè)到變化,就會(huì)觸發(fā) $scope上指定的回調(diào)函數(shù)

4.銷毀

通常來(lái)講如果一個(gè) $scope在視圖中不再需要, Angular會(huì)自己清理它.

ng-controller指令給所在的DOM元素創(chuàng)建了一個(gè)新的$scope對(duì)象练般,并將這個(gè)$scope對(duì)象包含進(jìn)外層DOM元素的$scope對(duì)象里健蕊。

在ng-app里,這個(gè)外層DOM元素的$scope對(duì)象踢俄,就是$rootScope對(duì)象缩功。這個(gè)scope鏈?zhǔn)沁@樣的:

所有scope都遵循原型繼承(prototypal inheritance),這意味著它們都能訪問(wèn)父scope們都办。對(duì)任何屬性和方法嫡锌,如果AngularJS在當(dāng)前scope上找不到,就會(huì)到父scope上去找琳钉,如果在父scope上也沒(méi)找到势木,就會(huì)繼續(xù)向上回溯,一直到$rootScope上歌懒。唯一的例外:有些指令屬性可以選擇性地創(chuàng)建一個(gè)獨(dú)立的scope啦桌,讓這個(gè)scope不繼承它的父scope們。

3、$watch:

? ? ? ? angularjs核心之一是雙向綁定甫男,那么這個(gè)雙向綁定是如何實(shí)現(xiàn)的呢且改?? 當(dāng)我們?cè)趧?chuàng)建出scope下的一個(gè)新屬性的時(shí)候,ng就會(huì)主動(dòng)為我們新屬性注冊(cè)$watch這個(gè)方法板驳,$watch用來(lái)監(jiān)聽的數(shù)據(jù)變化又跛,當(dāng)數(shù)據(jù)變化之后,就立即把view和scope上數(shù)據(jù)同步若治。AngularJS就能夠自動(dòng)注冊(cè)并監(jiān)聽變量的改變慨蓝。AngularJS會(huì)首先將在{{ }}中聲明的表達(dá)式編譯成函數(shù)并調(diào)用$watch方法。

?$watch是一個(gè)scope函數(shù)端幼,用于監(jiān)聽模型變化

?$watch(watchExpression, listener, objectEquality){ ... };

?watchExpression:$watch方法的第一個(gè)參數(shù)是一個(gè)函數(shù)礼烈,它通常被稱為watch函數(shù),它的返回值聲明需要監(jiān)聽的變量婆跑;

?listener:第二個(gè)參數(shù)是listener此熬,在變量發(fā)生改變的時(shí)候會(huì)被調(diào)用。和傳統(tǒng)的事件注冊(cè)和監(jiān)聽沒(méi)有什么本質(zhì)上的差別洽蛀,差別僅在于AngularJS能夠自動(dòng)注冊(cè)絕大多數(shù)的change事件并進(jìn)行監(jiān)聽摹迷,只要按照AngularJS要求的語(yǔ)法來(lái)寫HTML中的表達(dá)式代碼,即{{ }}郊供。 $watch方法為當(dāng)前scope注冊(cè)了一個(gè)watcher峡碉,這個(gè)watcher會(huì)被保存到一個(gè)scope內(nèi)部維護(hù)的數(shù)組中,即是$$watchers驮审。 watcher的主要目的是對(duì)scope上的某個(gè)屬性進(jìn)行監(jiān)控

? ? objectEquality:是否深度監(jiān)聽鲫寄,如果設(shè)置為true,它告訴Angular檢查所監(jiān)控的對(duì)象中每一個(gè)屬性的變化.? ?當(dāng)瀏覽器接收到可以被angular context處理的事件時(shí),$digest循環(huán)就會(huì)觸發(fā)疯淫。這個(gè)循環(huán)是由兩個(gè)更小的循環(huán)組合起來(lái)的地来。? ? 一個(gè)處理evalAsync隊(duì)列(這個(gè)沒(méi)有探究),另一個(gè)處理$watch隊(duì)列熙掺。$digest將會(huì)遍歷我們的$watch隊(duì)列未斑。如果有至少一個(gè)更新過(guò), 這個(gè)循環(huán)就會(huì)再次觸發(fā)币绩,直到所有的$watch都沒(méi)有變化蜡秽。這樣就能夠保證每個(gè)model都已經(jīng)不會(huì)再變化。 如果循環(huán)超過(guò)10次的話缆镣,它將會(huì)拋出一個(gè)異常芽突,防止無(wú)限循環(huán)。每次當(dāng)$digest循環(huán)結(jié)束時(shí)董瞻,DOM相應(yīng)地變化寞蚌。

? ? 例如我們按下按鈕觸發(fā)ng-click事件:

? 1、瀏覽器接收到一個(gè)事件,進(jìn)入angular context挟秤。

?2壹哺、 $digest循環(huán)開始執(zhí)行,查詢每個(gè)$watch是否變化煞聪。

? 3斗躏、 由于監(jiān)視$scope.name的$watch報(bào)告了變化逝慧,它會(huì)強(qiáng)制再執(zhí)行一次$digest循環(huán)昔脯。

? 4、 新的$digest循環(huán)沒(méi)有檢測(cè)到變化笛臣。

? ?5云稚、瀏覽器拿回控制權(quán),更新與$scope.name新值相應(yīng)部分的DOM沈堡。

? ? 6静陈、這里重要的是每一個(gè)進(jìn)入angular context的事件都會(huì)執(zhí)行一個(gè)$digest循環(huán),也就是說(shuō)每次我們輸入一個(gè)字母循環(huán)都會(huì)檢查整個(gè)頁(yè)面的所有$watch诞丽。? Angular會(huì)為我們自動(dòng)調(diào)用$apply鲸拥!因此當(dāng)點(diǎn)擊帶有ng-click的元素時(shí),事件就會(huì)被封裝到一個(gè)$apply調(diào)用僧免。? 比如有一個(gè)ng-model="foo"的輸入框刑赶,然后敲一個(gè)f,事件就會(huì)這樣調(diào)用$apply("foo = 'f';")懂衩,觸發(fā)$digest循環(huán)撞叨。

4、$state

? ? $state是ui-rooter的一項(xiàng)服務(wù)負(fù)責(zé)表示狀態(tài)以及它們之間的轉(zhuǎn)換浊洞。它還提供了接口來(lái)詢問(wèn)當(dāng)前狀態(tài)

常用的方法有:

$state.go(to, params, options) :轉(zhuǎn)換到新狀態(tài)的方便方法

$state.includes(stateOrName, params, options) :確定當(dāng)前活動(dòng)狀態(tài)是否等于或是狀態(tài)狀態(tài)子的方法牵敷。返回布爾值

$state.params: 返回狀態(tài)參數(shù)的對(duì)象$stateParams

$stateParams是一個(gè)對(duì)象,包含 url中每個(gè)參數(shù)的鍵/值法希。$stateParams可以為控制器或者服務(wù)提供 url的各個(gè)部分枷餐。

? ? 注意:$stateParams必須與一個(gè)控制器相關(guān),并且$stateParams中的“鍵/值”也必須事先在那個(gè)控制器的url屬性中有定義苫亦。

3.常見問(wèn)題

1毛肋、 如何自定義$watch?

2、 什么時(shí)候需要我們?nèi)フ{(diào)用$watch?

4.解決方案

1著觉、自定義自己的watches:

? ? angular.module("myApp",[]).controller('MainCtrl', function($scope) {$scope.name = "hello";$scope.updated = -1;$scope.$watch('name', function() {$scope.updated++;});});

//創(chuàng)造一個(gè)新的$watch的方法落君。第一個(gè)參數(shù)是一個(gè)字符串或者函數(shù)萍肆,在這里是只是一個(gè)字符串,就是我們要監(jiān)視的變量的名字,

//第二個(gè)參數(shù)是當(dāng)$watch說(shuō)我監(jiān)視的表達(dá)式發(fā)生變化后要執(zhí)行的嗓违。當(dāng)controller執(zhí)行到這個(gè)$watch時(shí)人乓,它會(huì)立即執(zhí)行一次

2、 取消 $watch :

$watch會(huì)影響性能問(wèn)題,特別是在移動(dòng)設(shè)備上油啤,在不需要時(shí)應(yīng)該清除

$watch函數(shù)本身返回一個(gè)函數(shù),所以,當(dāng)$watch不再需要的時(shí)候蟀苛,我們只需調(diào)用返回的函數(shù)即可:

.controller('MainCtrl',?function($scope)?{

$scope.updated?=?0;

$scope.stop?=?function()?{

textWatch();

};

var?textWatch?=?$scope.$watch('text',?function(newVal,?oldVal)?{

if?(newVal?===?oldVal)?{?return;?}

$scope.updated++;

});

});

2益咬、 什么時(shí)候需要我們?nèi)フ{(diào)用$watch?

被調(diào)用的事件沒(méi)有進(jìn)入angular context,$digest循環(huán)永遠(yuǎn)沒(méi)有執(zhí)行帜平。這種情況一般出現(xiàn)在指令的隔離作用域中

幽告,也會(huì)出現(xiàn)在異步執(zhí)行的函數(shù)體中。調(diào)用$watch需要通過(guò)$apply裆甩。

6.擴(kuò)展思考


指令中的scope三個(gè)值有什么用冗锁?

? ?false 共享作用域

? ? ? true 創(chuàng)建自己的作用域,并繼承父作用域

? ? ? {}創(chuàng)建隔離作用域

7.參考文獻(xiàn)

參考一:? Angular.js中使用$watch監(jiān)聽模型變化 http://yuankeqiang.lofter.com/post/8de51_1454f93

參考二:關(guān)于$watch應(yīng)用的一些小技巧?http://blog.csdn.net/u010451286/article/details/50635839

參考三: how the apply runs a digest? :http://angular-tips.com/blog/2013/08/watch-how-the-apply-runs-a-digest

參考四:深入解析AngularJS框架中$scope的作用與生命周期?http://www.jb51.net/article/80492.htm

參考五:-@ui-router——$state服務(wù)原版詳解? https://www.cnblogs.com/koleyang/p/4576419.html

問(wèn)題:


1嗤栓、如何移除不必要的$watch?

.controller('MainCtrl',?function($scope)?{

$scope.updated?=?0;

$scope.stop?=?function()?{

textWatch();

};

var?textWatch?=?$scope.$watch('text',?function(newVal,?oldVal)?{

if?(newVal?===?oldVal)?{?return;?}

$scope.updated++;

});

});

2冻河、1 ui-sref、$state.go 的區(qū)別ui-sref 一般使用在...茉帅;消息中心$state.go('someState')一般使用在 controller里面叨叙;.controller('firstCtrl', function($scope, $state) { $state.go('login'); });這兩個(gè)本質(zhì)上是一樣的東西,我們看ui-sref的源碼:...element.bind("click", function(e) { var button = e.which || e.button; if ( !(button > 1 || e.ctrlKey || e.metaKey || e.shiftKey || element.attr('target')) ) { var transition = $timeout(function() { // HERE we call $state.go inside of ui-sref $state.go(ref.state, params, options); });ui-sref最后調(diào)用的還是$state.go()方法

3堪澎、什么時(shí)候使用$watch

angular會(huì)為我們自動(dòng)執(zhí)行$watch擂错,當(dāng)指令中有獨(dú)立作用域,或者在異步函數(shù)中全封,改變的數(shù)據(jù)不在angular的執(zhí)行上下文马昙,就需要手動(dòng)調(diào)用$apply 來(lái)觸發(fā)$digest去執(zhí)行$watch

4、$scope 和$rootscope的區(qū)別是刹悴,$rootscope是$scope 的祖宗作用域


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末行楞,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子土匀,更是在濱河造成了極大的恐慌子房,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,807評(píng)論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件就轧,死亡現(xiàn)場(chǎng)離奇詭異证杭,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)妒御,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,284評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門解愤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人乎莉,你說(shuō)我怎么就攤上這事送讲〖轶裕” “怎么了?”我有些...
    開封第一講書人閱讀 169,589評(píng)論 0 363
  • 文/不壞的土叔 我叫張陵哼鬓,是天一觀的道長(zhǎng)监右。 經(jīng)常有香客問(wèn)我,道長(zhǎng)异希,這世上最難降的妖魔是什么健盒? 我笑而不...
    開封第一講書人閱讀 60,188評(píng)論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮称簿,結(jié)果婚禮上扣癣,老公的妹妹穿的比我還像新娘。我一直安慰自己予跌,他們只是感情好搏色,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,185評(píng)論 6 398
  • 文/花漫 我一把揭開白布善茎。 她就那樣靜靜地躺著券册,像睡著了一般。 火紅的嫁衣襯著肌膚如雪垂涯。 梳的紋絲不亂的頭發(fā)上烁焙,一...
    開封第一講書人閱讀 52,785評(píng)論 1 314
  • 那天,我揣著相機(jī)與錄音耕赘,去河邊找鬼骄蝇。 笑死,一個(gè)胖子當(dāng)著我的面吹牛操骡,可吹牛的內(nèi)容都是我干的九火。 我是一名探鬼主播,決...
    沈念sama閱讀 41,220評(píng)論 3 423
  • 文/蒼蘭香墨 我猛地睜開眼册招,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼岔激!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起是掰,我...
    開封第一講書人閱讀 40,167評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤虑鼎,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后键痛,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體炫彩,經(jīng)...
    沈念sama閱讀 46,698評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,767評(píng)論 3 343
  • 正文 我和宋清朗相戀三年絮短,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了江兢。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,912評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡丁频,死狀恐怖杉允,靈堂內(nèi)的尸體忽然破棺而出扔嵌,到底是詐尸還是另有隱情,我是刑警寧澤夺颤,帶...
    沈念sama閱讀 36,572評(píng)論 5 351
  • 正文 年R本政府宣布痢缎,位于F島的核電站,受9級(jí)特大地震影響世澜,放射性物質(zhì)發(fā)生泄漏独旷。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,254評(píng)論 3 336
  • 文/蒙蒙 一寥裂、第九天 我趴在偏房一處隱蔽的房頂上張望嵌洼。 院中可真熱鬧,春花似錦封恰、人聲如沸麻养。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,746評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)鳖昌。三九已至,卻和暖如春低飒,著一層夾襖步出監(jiān)牢的瞬間许昨,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,859評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工褥赊, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留糕档,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,359評(píng)論 3 379
  • 正文 我出身青樓拌喉,卻偏偏與公主長(zhǎng)得像速那,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子尿背,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,922評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容