AngularJS 控制器中的“this"与 $scope [英] 'this' vs $scope in AngularJS controllers

查看:23
本文介绍了AngularJS 控制器中的“this"与 $scope的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在AngularJS主页的.(它通常不会从 HTML 中遇到指令的作用域继承原型.)

现在,pane 指令的链接函数想要与 tabs 指令通信(这实际上意味着它需要以某种方式影响 tabs 隔离 $scope).可以使用事件,但另一种机制是让窗格指令 require 成为选项卡控制器.(似乎没有pane指令require标签$scope的机制.)

所以,这就引出了一个问题:如果我们只能访问选项卡控制器,我们如何访问选项卡隔离 $scope(这是我们真正想要的)?

好吧,红色虚线就是答案.addPane() 函数的范围"(我在这里指的是 JavaScript 的函数范围/闭包)为函数提供了对标签隔离 $scope 的访问权限.即,addPane() 可以访问上图中的tabs IsolateScope",因为在定义 addPane() 时创建了一个闭包.(如果我们改为在选项卡 $scope 对象上定义 addPane(),则窗格指令将无法访问此函数,因此它无法与选项卡 $scope 通信.)

回答问题的另一部分:$scope 在控制器中是如何工作的?:

在 $scope 上定义的函数中,this 设置为在调用函数的位置/时间生效的 $scope".假设我们有以下 HTML:

<a ng-click="logThisAndScope()">记录this"和$scope</a>- 父范围<div ng-controller="ChildCtrl"><a ng-click="logThisAndScope()">记录this"和$scope</a>- 子范围

ParentCtrl(单独)有

$scope.logThisAndScope = function() {console.log(this, $scope)}

单击第一个链接将显示 this$scope 是相同的,因为调用函数时的作用域" 是与 ParentCtrl 关联的范围.

单击第二个链接将显示 this$scope 相同,因为作用域在function was called" 是与 ChildCtrl 关联的范围.所以在这里,this 被设置为ChildCtrl$scope.在方法内部,$scope 仍然是 ParentCtrl 的 $scope.

小提琴

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

In the "Create Components" section of AngularJS's homepage, there is this example:

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);
  }
}

Notice how the select method is added to $scope, but the addPane method is added to this. If I change it to $scope.addPane, the code breaks.

The documentation says that there in fact is a difference, but it doesn't mention what the difference is:

Previous versions of Angular (pre 1.0 RC) allowed you to use this interchangeably with the $scope method, but this is no longer the case. Inside of methods defined on the scope this and $scope are interchangeable (angular sets this to $scope), but not otherwise inside your controller constructor.

How does this and $scope work in AngularJS controllers?

解决方案

"How does this and $scope work in AngularJS controllers?"

Short answer:

  • this
    • When the controller constructor function is called, this is the controller.
    • When a function defined on a $scope object is called, this is the "scope in effect when the function was called". This may (or may not!) be the $scope that the function is defined on. So, inside the function, this and $scope may not be the same.
  • $scope
    • Every controller has an associated $scope object.
    • A controller (constructor) function is responsible for setting model properties and functions/behaviour on its associated $scope.
    • Only methods defined on this $scope object (and parent scope objects, if prototypical inheritance is in play) are accessible from the HTML/view. E.g., from ng-click, filters, etc.

Long answer:

A controller function is a JavaScript constructor function. When the constructor function executes (e.g., when a view loads), this (i.e., the "function context") is set to the controller object. So in the "tabs" controller constructor function, when the addPane function is created

this.addPane = function(pane) { ... }

it is created on the controller object, not on $scope. Views cannot see the addPane function -- they only have access to functions defined on $scope. In other words, in the HTML, this won't work:

<a ng-click="addPane(newPane)">won't work</a>

After the "tabs" controller constructor function executes, we have the following:

The dashed black line indicates prototypal inheritance -- an isolate scope prototypically inherits from Scope. (It does not prototypically inherit from the scope in effect where the directive was encountered in the HTML.)

Now, the pane directive's link function wants to communicate with the tabs directive (which really means it needs to affect the tabs isolate $scope in some way). Events could be used, but another mechanism is to have the pane directive require the tabs controller. (There appears to be no mechanism for the pane directive to require the tabs $scope.)

So, this begs the question: if we only have access to the tabs controller, how do we get access to the tabs isolate $scope (which is what we really want)?

Well, the red dotted line is the answer. The addPane() function's "scope" (I'm referring to JavaScript's function scope/closures here) gives the function access to the tabs isolate $scope. I.e., addPane() has access to the "tabs IsolateScope" in the diagram above because of a closure that was created when addPane() was defined. (If we instead defined addPane() on the tabs $scope object, the pane directive would not have access to this function, and hence it would have no way to communicate with the tabs $scope.)

To answer the other part of your question: how does $scope work in controllers?:

Within functions defined on $scope, this is set to "the $scope in effect where/when the function was called". Suppose we have the following 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>

And the ParentCtrl (Solely) has

$scope.logThisAndScope = function() {
    console.log(this, $scope)
}

Clicking the first link will show that this and $scope are the same, since "the scope in effect when the function was called" is the scope associated with the ParentCtrl.

Clicking the second link will reveal this and $scope are not the same, since "the scope in effect when the function was called" is the scope associated with the ChildCtrl. So here, this is set to ChildCtrl's $scope. Inside the method, $scope is still the ParentCtrl's $scope.

Fiddle

I try to not use this inside of a function defined on $scope, as it becomes confusing which $scope is being affected, especially considering that ng-repeat, ng-include, ng-switch, and directives can all create their own child scopes.

这篇关于AngularJS 控制器中的“this"与 $scope的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆