在AngularJS主页的“创建组件”部分,有这样一个例子:
controller: function($scope, $element) {
var panes = $scope.panes = [];
$scope.select = function(pane) {
angular.forEach(panes, function(pane) {
pane.selected = false;
});
pane.selected = true;
}
this.addPane = function(pane) {
if (panes.length == 0) $scope.select(pane);
panes.push(pane);
}
}
注意select
方法是如何添加到$scope
的,而addpane
方法是如何添加到this
的。如果我将其更改为$scope.addpane
,则代码中断。
文档中说实际上有区别,但没有提到区别是什么:
Angular的早期版本(1.0 RC之前)允许您将此
与$scope
方法互换使用,但现在不再是这样了。在作用域上定义的方法中,this
和$scope
是可互换的(角度将this
设置为$scope
),但在控制器构造函数中则不可互换。
this
和$scope
如何在AngularJS控制器中工作?
“this
和$scope
如何在AngularJS控制器中工作?”
简短的回答:
this
此
是控制器。$scope
对象上定义的函数时,this
是“调用函数时有效的作用域”。这可能(也可能不会!)是定义函数的$scope
。因此,在函数内部,this
和$scope
可能不相同。$scope
对象。$scope
上设置模型属性和函数/行为。$scope
对象上定义的方法(以及父作用域对象,如果正在使用原型继承)才能从HTML/视图访问。例如,从ng-click
,筛选器等长答:
控制器函数是一个JavaScript构造函数。当构造函数函数执行时(例如,当一个视图加载时),this
(即“函数上下文”)被设置为控制器对象。所以在“tabs”控制器构造函数中,当创建addPane函数时
this.addPane = function(pane) { ... }
它是在controller对象上创建的,而不是在$Scope上创建的。视图无法看到addPane函数--它们只能访问在$Scope上定义的函数。换句话说,在HTML中,这是行不通的:
<a ng-click="addPane(newPane)">won't work</a>
在“tabs”控制器构造函数执行之后,我们有以下内容:
黑线表示原型继承--隔离作用域典型地从作用域继承。(它并不典型地从HTML中遇到指令的有效作用域继承。)
现在,pane指令的link函数希望与tabs指令通信(这实际上意味着它需要以某种方式影响标签隔离$scope)。可以使用事件,但另一种机制是让窗格指令require
成为tabs控制器。(窗格指令似乎没有require
选项卡$scope的机制。)
因此,这就引出了一个问题:如果我们只能访问tabs控制器,那么我们如何访问isolate$scope选项卡(这是我们真正想要的)?
红色虚线就是答案。addPane()函数的“scope”(这里指的是JavaScript的scope/closures函数)为该函数提供了对isolate$scope选项卡的访问权限。即,addPane()可以访问上面关系图中的“Tabs IsolateScope”,因为在定义addPane()时创建了一个闭包。(如果我们在tabs$scope对象上定义addPane(),则pane指令将不能访问该函数,因此它将无法与tabs$scope通信。)
要回答问题的另一部分:$scope如何在控制器中工作?
:
在$scope上定义的函数中,this
被设置为“函数被调用的位置/时间有效的$scope”。假设我们有以下HTML:
<div ng-controller="ParentCtrl">
<a ng-click="logThisAndScope()">log "this" and $scope</a> - parent scope
<div ng-controller="ChildCtrl">
<a ng-click="logThisAndScope()">log "this" and $scope</a> - child scope
</div>
</div>
而父Ctrl
(仅)具有
$scope.logThisAndScope = function() {
console.log(this, $scope)
}
单击第一个链接将显示this
和$scope
是相同的,因为“调用函数时有效的作用域”是与parentCtrl
相关联的作用域。
单击第二个链接将显示thes
和$scope
不相同,因为“调用函数时有效的作用域”是与ChildCtrl
相关联的作用域。因此在这里,this
被设置为childCtrl
的$scope
。在该方法内部,$scope
仍然是ParentCtrl
的$scope。
小提琴
我尽量不在$scope上定义的函数中使用this
,因为会让人混淆哪个$scope受到了影响,特别是考虑到ng-repeat,ng-include,ng-switch和指令都可以创建它们自己的子作用域。
之所以将“add pane”分配给它,是因为
指令。
pane
指令需要:'^tabs',它将父指令中的tabs控制器对象放入链接函数中。
addpane
被分配给this
,以便pane
链接函数可以看到它。然后在Pane
链接函数中,AddPane
只是Tabs
控制器的一个属性,它只是TabsControllerObject.AddPane。因此pane指令的链接函数可以访问tabs控制器对象,从而访问addPane方法。
我希望我的解释足够清楚。这有点难以解释。
我刚刚读了一篇关于两者之间区别的非常有趣的解释,以及越来越多的人倾向于将模型附加到控制器上,并对控制器进行别名以将模型绑定到视图。http://toddmotto.com/digging-into-angulars-controller-as-syntax/是这篇文章。
他没有提到这一点,但是在定义指令时,如果您需要在多个指令之间共享一些东西,并且不想要服务(在服务是一个麻烦的合法情况下),那么就将数据附加到父指令的控制器上。
$scope
服务提供了许多有用的东西,$watch
是最明显的,但是如果您需要将数据绑定到视图,那么在模板中使用普通控制器和“controller as”就可以了,而且可以说是更可取的。