“ AngularJS 控制器是如何this
工作的?”$scope
简短的回答:
this
- 当控制器的构造函数被调用时,
this
就是控制器。
- 当调用在
$scope
对象上定义的函数时,this
是“调用函数时的有效范围”。这可能(也可能不是!)$scope
是定义函数的那个。所以,里面的函数,this
和$scope
可能不一样。
$scope
- 每个控制器都有一个关联的
$scope
对象。
- 控制器(构造函数)函数负责在其关联的
$scope
.
- 只有在这个
$scope
对象上定义的方法(和父范围对象,如果原型继承在起作用)可以从 HTML/view 访问。例如,来自ng-click
、过滤器等。
长答案:
控制器函数是 JavaScript 构造函数。当构造函数执行时(例如,当加载视图时),this
(即,“函数上下文”)被设置为控制器对象。所以在“tabs”控制器构造函数中,当addPane函数被创建时
this.addPane = function(pane) { ... }
它是在控制器对象上创建的,而不是在 $scope 上。视图无法看到 addPane 函数——它们只能访问在 $scope 上定义的函数。换句话说,在 HTML 中,这是行不通的:
<a ng-click="addPane(newPane)">won't work</a>
在“tabs”控制器构造函数执行后,我们有以下内容:
黑色虚线表示原型继承——隔离作用域原型继承自Scope。(它不会原型继承自在 HTML 中遇到指令的有效范围。)
现在,pane 指令的链接函数想要与 tabs 指令通信(这实际上意味着它需要以某种方式影响 tabs 隔离 $scope)。可以使用事件,但另一种机制是让窗格指令require
选项卡控制器。(似乎没有针对require
选项卡 $scope 的窗格指令的机制。)
所以,这就引出了一个问题:如果我们只能访问选项卡控制器,我们如何访问选项卡隔离 $scope(这是我们真正想要的)?
嗯,红色虚线就是答案。addPane() 函数的“作用域”(我在这里指的是 JavaScript 的函数作用域/闭包)使函数能够访问选项卡隔离 $scope。即,addPane() 可以访问上图中的“选项卡 IsolateScope”,因为在定义 addPane() 时创建了一个闭包。(如果我们改为在选项卡 $scope 对象上定义 addPane(),则窗格指令将无法访问此函数,因此它无法与选项卡 $scope 通信。)
要回答您问题的另一部分how does $scope work in controllers?
:
在 $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>
并且ParentCtrl
(仅)有
$scope.logThisAndScope = function() {
console.log(this, $scope)
}
单击第一个链接将显示this
和$scope
是相同的,因为“调用函数时生效的范围”是与ParentCtrl
.
单击第二个链接将显示this
并且$scope
不一样,因为“调用函数时生效的范围”是与ChildCtrl
. 所以在这里,this
设置为ChildCtrl
's $scope
。在方法内部,$scope
仍然是ParentCtrl
's $scope.
小提琴
我尽量不要this
在 $scope 上定义的函数内部使用,因为它会混淆哪个 $scope 受到影响,特别是考虑到 ng-repeat、ng-include、ng-switch 和指令都可以创建自己的子范围。