轉自:http://www.lovelucy.info/understanding-scopes-in-angularjs.html
angularjs 中的scope繼承關系
ng-include
假設在我們的 controller 中,
|
HTML 為:
|
每一個 ng-include 會生成一個子 Scope,每個子 Scope 都繼承父 Scope。
輸入(比如”77″)到第一個 input 文本框,則子 Scope 將獲得一個新的 myPrimitive 屬性,覆蓋掉父 Scope 的同名屬性。這可能和你預想的不一樣。
輸入(比如”99″)到第二個 input 文本框,并不會在子 Scope 創建新的屬性,因為 tpl2.html 將 model 綁定到了一個對象屬性(an object property),原型繼承在這時發揮了作用,ngModel 尋找對象 myObject 并且在它的父 Scope 中找到了。
如果我們不想把 model 從 number 基礎類型改為對象,我們可以用 $parent 改寫第一個模板:
|
輸入(比如”22″)到這個文本框也不會創建新屬性了。model 被綁定到了父 scope 的屬性上(因為 $parent 是子 Scope 指向它的父 Scope 的一個屬性)。
對于所有的 scope (原型繼承的或者非繼承的),Angular 總是會通過 Scope 的 $parent, $$childHead 和 $$childTail 屬性記錄父-子關系(也就是繼承關系),圖中為簡化而未畫出這些屬性。
在沒有表單元素的情況下,另一種方法是在父 Scope 中定義一個函數來修改基本數據類型。因為有原型繼承,子 Scope 確保能夠調用這個函數。例如,
|
查看 DEMO。參考?StackOverflow。
ng-switch
ng-switch 的原型繼承和 ng-include 一樣。所以如果你需要對基本類型數據進行雙向綁定,使用 $parent,或者將其改為 object 對象并綁定到對象的屬性,防止子 Scope 覆蓋父 Scope 的屬性。
參考?AngularJS, bind scope of a switch-case?
ng-repeat
ng-repeat 有一點不一樣。假設在我們的 controller 里:
|
還有 HTML:
|
對于每一個 Item,ng-repeat 創建新的 Scope,每一個 Scope 都繼承父 Scope,但同時 item 的值也被賦給了新 Scope 的新屬性(新屬性的名字為循環的變量名)。Angular ng-repeat 的源碼實際上是這樣的:
|
如果 item 是一個基礎數據類型(就像 myArrayOfPrimitives),本質上它的值被復制了一份賦給了新的子 scope 屬性。改變這個子 scope 屬性值(比如用 ng-model,即?num
)不會改變父 scope 引用的 array。所以上面第一個 ng-repeat 里每一個子 scope 獲得的?num
?屬性獨立于 myArrayOfPrimitives 數組:
這樣的 ng-repeat 和你預想中的不一樣。在 Angular 1.0.2 及更早的版本,向文本框中輸入會改變灰色格子的值,它們只在子 Scope 中可見。Angular 1.0.3+ 以后,輸入文本不會再有任何作用了。(參考StackOverflow 上的解釋)我們希望的是輸入能改變 myArrayOfPrimitives 數組,而不是子 Scope 里的屬性。為此我們必須將 model 改為一個關于對象的數組(array of objects)。
所以如果 item 是一個對象,則對于原對象的一個引用(而非拷貝)被賦給了新的子 Scope 屬性。改變子 Scope 屬性的值(使用 ng-model,即 obj.num)也就改變了父 Scope 所引用的對象。所以上面第二個 ng-repeat 可表示為:
這才是我們想要的。輸入到文本框即會改變灰色格子的值,該值在父 Scope 和子 Scope 均可見。
總結
一共有四種 Scope:
- 普通進行原型繼承的 Scope —— ng-include, ng-switch, ng-controller, directive with?
scope: true
- 普通原型繼承的 Scope 但拷貝賦值 —— ng-repeat。 每個 ng-repeat 的循環都創建新的子 Scope,并且子 Scope 總是獲得新的屬性。
- 獨立的 isolate scope —— directive with?
scope: {...}
。它不是原型繼承,但 ‘=’, ‘@’ 和 ‘&’ 提供了訪問父 Scope 屬性的機制。 - transcluded scope —— directive with?
transclude: true
。它也遵循原型繼承,但它同時是任何 isolate scope 的兄弟。
對于所有的 Scope,Angular 總是會通過 Scope 的 $parent, $$childHead 和 $$childTail 屬性記錄父-子關系。
?