作用域1.0
控制器與$scope
瞭解作用域,首先要理解angular js的控制器。控制器的主要職責是初始化作用域實例,那麼問題來了,什麼是作用域實例呢?學過Java的人都知道,Java中可以將很多方法和需要的屬性封裝到一個類中,方便其他類調用,在我個人看來,angular js裏面就定義了一個scope類,而我們在html裏面使用ng-controller標籤(這個標籤是由指令(Directives)定義的)時,會自動創建一個scope類的實例。這裏就從angular js的運行來談,由於我之前的學習時針對的Java和c語言,所以就拿Java來做對比,在dom加載完後,瀏覽器發現ng-app標籤後,會先創建一個根作用域$root(這個root可以看成是Java中的類繼承的根類),然後看到了ng-controller,於是又創建一個$scope(此時的$scope完全繼承自$root,也就是說可以用$root的所有屬性),也就是說在一個標籤內的另一個標籤如果創建作用域,如果沒指明父作用域,那麼它們之間就有個繼承關係,說到這裏,再回到控制器來,它的職責有個亮點“初始化”,也就是說控制器其實就是用來給$scope的屬性賦值(這裏的值可爲數組,對象等,這個是js特有的特點)和方法。
ng-repeat怎麼創建作用域
ng-repeat我在第一次接觸時就喜歡上了它,因爲有了它,我可以很簡單的實現很多想法,它的作用是重複創建所在的標籤,這個時候問題又來了,它這個語法"XXX in XXXs"(後面那個就表示複數啊)按照我上面說的原則,對應每個XXX,都有個新變量要暴露給$scope,而又不能覆蓋之前的變量值,這個時候同名(XXX)的屬性怎麼創建作用域(屬性也有自己的作用域,因爲js的特點,屬性也可以爲對象等),angular js爲了解決這個問題,使用了一個叫“模型值”(model values)的東東,用以辨別同名的屬性作用域(也就是3個數字,如001)。
嘗試
對於以上的學習,我做了如下的嘗試來驗證:
test.html
- <span style="font-size:18px;"><html >
- <head>
- <script type="text/javascript" src="angular.min.js"></script>
- <script type="text/javascript" src="test.js"></script>
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
- </head>
- <body ng-app ng-init="appName='app'">
- $root.appName={{appName}}
- <div ng-controller="aCtrl">
- <hr>
- 控制器作用域<br>
- 使用父作用域的appName:<input ng-model="appName">
- $root.appName:{{appName}}
- <br/>對names進行ng-repeat,給集合每個元素創建一個叫a的屬性作用域
- <div ng-repeat="a in names">
- <br/>
- 使用a獲取:{{a}}<br/>
- 使用a.name獲取:{{a.name}}<br>
- </div>
- </div>
- </body>
- </html></span>
- <span style="font-size:18px;">var aCtrl = function($scope){
- $scope.names = [
- {name:"1"},
- {name:"2"},
- ];
- };</span>
下面是ng-app($root)的作用域, 可以看到我定義的屬性appName。
再來看ng-controller($scope)的作用域,它裏面也可以看到$root的appName,而且多了個屬性names(這是我通過js給$scope創建的屬性)
下面再來看看ng-controller中通過ng-repeat創建的屬性作用域
第一個屬性作用域,在裏面有父作用域中的appName和names,而且又多了個a的屬性,注意names集合中對象的值裏多了個我在js裏沒有定義的$$hashKey,這個東西應該就是model values。
第二個屬性作用域也就大同小異了,可以看到唯一的區別就是$$hashKey的值
既然子作用域可以用父作用域的值,那我就不免想到用子作用域更改值,會產生什麼影響,以下是改變後瀏覽器的變化
因爲我的input標籤與appName實現了雙向數據綁定,可以看到我更改appName後,分割線上的{{appName}}無改變,而ng-controller($scope)中的{{appName}}改變了。
來看看這個時候ng-app($root)的作用域,很明顯appName沒有改變,那麼ng-controller($scope)裏的appName爲什麼變了呢?
帶着疑問,我又看了ng-controller($scope)的作用域,沒錯,裏面的appName改變了,再做了相關的查閱後,總結出一個原因:ng-controller生成的作用域創建了新的appName變量,而不是去修改$root中設定的appName的值,而如果想要修改,可以利用<input ng-model="$parent.appName">明確的引用父作用域來實現。
以上是這篇筆記中的所有嘗試。
TIP
anguler js中官方定義的屬性前都有個$符號,所以呢,我們創建自己的變量時就最好不要加$了,這樣也方便查看,然後Firefox有個查看angular js作用域的工具,叫做Angscope,很有用,我就拿它來驗證自己對作用域的猜想。
sublime的一個快捷鍵,alt+shift+數字,可以實現分屏,蠻實用的。