"this" vs $scope在AngularJS控制器中的使用
"this" vs $scope在AngularJS控制器中的使用
在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之前)允许您将this与$scope方法交替使用,但现在不再是这种情况。在作用域中定义的方法内,this和$scope是可互换的(angular将this设置为$scope),但其他情况下在您的控制器构造函数中不是这样。
this和$scope在AngularJS控制器中如何工作呢?
“AngularJS控制器中的
this
和$scope
是如何工作的?”
简短回答:
this
- 当调用控制器构造函数时,
this
指代的是控制器本身。 - 当调用一个在
$scope
对象上定义的函数时,this
指代的是“调用该函数时所生效的作用域”。这可能(或可能不)是该函数所在的$scope
对象。因此,在函数内部,this
和$scope
不一定相同。
- 当调用控制器构造函数时,
$scope
- 每个控制器都有一个关联的
$scope
对象。 - 控制器(构造函数)负责在其关联的
$scope
对象上设置模型属性、函数/行为。 - 只有在此
$scope
对象(和可能存在的父作用域对象,如果使用原型继承)上定义的方法可以从HTML/视图中访问。例如,从ng-click
、过滤器等。
- 每个控制器都有一个关联的
长答案:
控制器函数是一个JavaScript构造函数。当构造函数执行时(例如,当视图加载时),this
(即“函数上下文”)被设置为控制器对象。因此,在“标签页”控制器构造函数中创建addPane函数时
this.addPane = function(pane) { ... }
它是在控制器对象上创建的,而不是在$scope
对象上创建的。视图无法看到addPane函数——它们只能访问在$scope
上定义的函数。换句话说,在HTML中,这是行不通的:
won't work
在“标签页”控制器构造函数执行后,我们有以下内容:
虚线黑线表示原型继承——独立作用域原型继承自Scope。(它不是从HTML中遇到的作用域原型继承。)
现在,面板指令的link函数想要与标签指令通信(这实际上意味着它需要以某种方式影响标签独立$scope)。事件可以使用,但另一种机制是让面板指令require
标签控制器。(似乎没有机制让面板指令require
标签$scope。)
所以,这就有一个问题:如果我们只能访问标签控制器,那么如何访问标签独立$scope(这是我们真正想要的)?
好吧,红色虚线就是答案。添加Pane()函数的“作用域”(我指的是JavaScript中的函数作用域/闭包)给该函数访问标签独立$scope。也就是说,addPane()可以访问上面这个图中的“标签IsolateScope”,因为在定义addPane()时创建了一个闭包。(如果我们将addPane()定义在标签$scope对象上,面板指令将无法访问该函数,因此它将无法与标签$scope进行通信。)
回答你的问题的另一部分:控制器中的$scope是如何工作的?
:
在$scope中定义函数时,this
被设置为“函数调用时/处生效的$scope”。假设我们有以下HTML代码:
log "this" and $scope - parent scope log "this" and $scope - child scope
并且ParentCtrl
(仅)有:
$scope.logThisAndScope = function() { console.log(this, $scope) }
点击第一个链接将显示this
和$scope
是相同的,因为“函数调用时生效的$scope”是与ParentCtrl
相关联的$scope。
点击第二个链接将显示this
和$scope
不相同,因为“函数调用时/处生效的$scope”是与ChildCtrl
相关联的$scope。因此,在这里,this
被设置为ChildCtrl
的$scope
。 在方法中,$scope
仍然是ParentCtrl
的$scope。
我尝试不在$scope中定义函数时使用this
,因为这会使得哪个$scope被影响变得混乱,特别是考虑到ng-repeat、ng-include、ng-switch和指令都可以创建它们自己的子作用域。