在"Create Components" section of AngularJS's homepage中,有这个例子:
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之前版本)允许您与$ scope方法互换使用,但现在不再是这种情况了 . 在范围内定义的方法内部,此范围和$ scope是可互换的(角度设置为$ scope),但在控制器构造函数中则不然 .
this
和 $scope
如何在AngularJS控制器中工作?
7 回答
'addPane'分配给它的原因是因为
<pane>
指令 .pane
指令执行require: '^tabs'
,它将来自父指令的tabs控制器对象放入link函数中 .addPane
被分配给this
,以便pane
链接功能可以看到它 . 然后在pane
link函数中,addPane
只是tabs
控制器的一个属性,它的's just tabsControllerObject.addPane. So the pane directive'链接函数可以访问tabs控制器对象,因此可以访问addPane方法 .我希望我的解释很清楚......这很难解释 .
$ scope有一个不同的'this'然后是控制器'this' . 因此,如果你把一个console.log(这个)放在控制器中它给你一个对象(控制器),this.addPane()将addPane方法添加到控制器对象 . 但$ scope具有不同的范围,其范围内的所有方法都需要由$ scope.methodName()加入 .
this.methodName()
内部控制器意味着在控制器对象内添加方法 .$scope.functionName()
是HTML和内部将此代码粘贴到编辑器中并打开控制台以查看...
Short answer :
this
调用控制器构造函数时,
this
是控制器 .当调用
$scope
对象上定义的函数时,this
是"scope in effect when the function was called" . 这可能(或可能不是!)是定义函数的$scope
. 因此,在函数内部,this
和$scope
可能 not 是相同的 .$scope
每个控制器都有一个关联的
$scope
对象 .控制器(构造函数)函数负责在其关联的
$scope
上设置模型属性和函数/行为 .只能从HTML /视图访问此
$scope
对象上定义的方法(以及父范围对象,如果原型继承正在进行中) . 例如,来自ng-click
,过滤器等Long answer :
控制器函数是JavaScript构造函数 . 当构造函数执行时(例如,当视图加载时),
this
(即,"function context")被设置为控制器对象 . 所以在"tabs"控制器构造函数中,创建了addPane函数它是在控制器对象上创建的,而不是在$ scope上创建的 . 视图无法看到addPane函数 - 它们只能访问$ scope上定义的函数 . 换句话说,在HTML中,这将不起作用:
执行“tabs”控制器构造函数后,我们有以下内容:
黑色虚线表示原型继承 - 原型继承自Scope的隔离范围 . (它没有原型地继承HTML中遇到指令的有效范围 . )
现在,窗格指令的链接函数想要与tabs指令进行通信(这实际上意味着它需要以某种方式影响选项卡隔离$ scope) . 可以使用事件,但另一种机制是使窗格指令
require
为tabs控制器 . (似乎没有窗格指令的机制require
标签$ scope . )所以,这就引出了一个问题:如果我们只能访问选项卡控制器,那么我们如何访问选项卡隔离$ scope(这是我们真正想要的)?
嗯,红色虚线就是答案 . addPane()函数的“范围”(我指的是JavaScript的函数范围/闭包)给函数访问选项卡隔离$ scope . 即,addPane()可以访问上图中的“tabs IsolateScope”,因为在定义addPane()时创建了一个闭包 . (如果我们在选项卡$ scope对象上定义了addPane(),则窗格指令将无法访问此函数,因此它无法与选项卡$ scope通信 . )
要回答您问题的其他部分:
how does $scope work in controllers?
:在$ scope中定义的函数内,
this
设置为"the $scope in effect where/when the function was called" . 假设我们有以下HTML:并且
ParentCtrl
(Solely)有单击第一个链接将显示
this
和$scope
是相同的,因为“调用函数时生效的范围”是与ParentCtrl
关联的范围 .单击第二个链接将显示
this
和$scope
是 not 相同,因为“调用函数时有效的范围”是与ChildCtrl
关联的范围 . 所以在这里,this
被设置为ChildCtrl
的$scope
. 在方法内部,$scope
仍然是ParentCtrl
的$ scope .Fiddle
我尝试不在$ scope中定义的函数内部使用
this
,因为令人困惑的是哪个$ scope受到影响,特别是考虑到ng-repeat,ng-include,ng-switch和指令都可以创建自己的子作用域 .要恢复这种行为(有人知道它为什么会改变吗?)你可以添加:
在控制器功能结束时(前提是$ scope注入此控制器功能) .
这通过控制器对象访问父作用域具有很好的效果,您可以使用
require: '^myParentDirective'
获取子控制器对象在本课程(https://www.codeschool.com/courses/shaping-up-with-angular-js)中,他们解释了如何使用"this"等许多其他内容 .
如果通过“this”方法向控制器添加方法,则必须在视图中使用控制器名称“dot”将其称为属性或方法 .
例如,在视图中使用您的控制器,您可能具有以下代码:
我建议你阅读以下帖子:AngularJS: "Controller as" or "$scope"?
它很好地描述了使用“Controller as”在“$ scope”上公开变量的优点 .
我知道你具体问过方法而不是变量,但我认为最好坚持使用一种技术并与之保持一致 .
所以我认为,由于帖子中讨论的变量问题,最好只使用“Controller as”技术并将其应用于方法 .
我刚刚阅读了关于两者之间差异的一个非常有趣的解释,并且越来越倾向于将模型附加到控制器并且将控制器别名为控制器以将模型绑定到视图 . http://toddmotto.com/digging-into-angulars-controller-as-syntax/是文章 . 他没有想要一个服务(有合理的情况下服务是麻烦的)然后将数据附加到父指令's controller. The $scope service provides plenty of useful things, $watch being the most obvious, but if all you need to to bind data to the view, using the plain controller and '控制器,因为模板中的'很好,并且可以说是更好的 .