在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,则代码会中断。
select
$scope
addPane
this
$scope.addPane
该文档说实际上存在差异,但没有提及差异是什么:
以前版本的 Angular(1.0 RC 之前)允许您this与该方法互换使用$scope,但现在情况不再如此。在范围内定义的方法内部this并且$scope是可互换的(角度设置this为$scope),但在控制器构造函数内部则不能。
AngularJS 控制器是如何this工作的?$scope
“ AngularJS 控制器是如何this工作的?”$scope
简短的回答 :
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 的窗格指令的机制。)
require
所以,这就引出了一个问题:如果我们只能访问选项卡控制器,我们如何访问选项卡隔离 $scope(这是我们真正想要的)?
嗯,红色虚线就是答案。addPane() 函数的“作用域”(我在这里指的是 JavaScript 的函数作用域/闭包)提供了对选项卡隔离 $scope 的函数访问权限。即,addPane() 可以访问上图中的“选项卡 IsolateScope”,因为在定义 addPane() 时创建了一个闭包。(如果我们改为在选项卡 $scope 对象上定义 addPane(),则窗格指令将无法访问此函数,因此它无法与选项卡 $scope 进行通信。)
要回答您问题的另一部分how does $scope work in controllers?:
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(仅)有
ParentCtrl
$scope.logThisAndScope = function() { console.log(this, $scope) }
单击第一个链接将显示this和$scope是相同的,因为“ 调用函数时生效的 范围”是与ParentCtrl.
单击第二个链接将显示this并且$scope不 一样 ,因为“ 调用函数时生效的 范围”是与ChildCtrl. 所以在这里,this设置为ChildCtrl‘s $scope。在方法内部,$scope仍然是ParentCtrl‘s $scope.
ChildCtrl
jsfiddle
我尽量不要this在 $scope 上定义的函数内部使用,因为它会混淆哪个 $scope 受到影响,特别是考虑到 ng-repeat、ng- include、ng-switch 和指令都可以创建自己的子范围。