![the the](https://c1.lmlphp.com/image/static/default_avatar.gif)
本文介绍了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:
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的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!