小编典典

AngularJS 控制器中的“this”与 $scope

all

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是可互换的(角度设置this$scope),但在控制器构造函数内部则不能。

AngularJS 控制器是如何this工作的?$scope


阅读 121

收藏
2022-02-28

共1个答案

小编典典

“ 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.

jsfiddle

我尽量不要this在 $scope 上定义的函数内部使用,因为它会混淆哪个 $scope 受到影响,特别是考虑到 ng-repeat、ng-
include、ng-switch 和指令都可以创建自己的子范围。

2022-02-28